#include #include #include #include "inc/mob.h" #include "inc/benchmark.h" #include "inc/routines.h" #include "inc/genCode.h" /* global variables externally defined */ extern struct globalSystem sys; /* local defines */ #define MIN_SETS 256 /* minimum number of sets to perform between read calls */ /* local prototypes */ static int tlbAssocRun( char *array, unsigned int maxMem, unsigned int minPage, type_t type ); static double tlbAssocAccess( char *array, unsigned int assoc, unsigned int stride, type_t type ); static double tlbAssocCtrl( char *array, unsigned int assoc, unsigned int stride, type_t type ); #if 0 static size_t getAvailUserMem(){ /* temporary hack...before actually adding the test to detect it...*/ return( 40 * M_SIZE( M_1M ) ); } #endif /* Determine associativity for each TLB. return - 0 if successful, non-zero if failed */ int tlbAssoc( void ){ int error = 0; /* Minimum page size, to "ensure" that we hit in the same TLB entry... by doing it BIG we can guarantee that, but we can't do it arbitrarily big because then we would have to allocate a huge chunk of memory to be able to jump this size, through the different possible assocs */ unsigned int minPage = M_SIZE(M_512K); unsigned int workSize = sys.arraySize; /* ensure block of memory large enough for working set */ if( arrayPrepare( workSize ) ) handleError( "checking memory in tlbAssoc", EnoMem ); show( VERB_DEBUG, "Working Size for TLB Associativity %d bytes\n", (unsigned int)workSize ); show( VERB_DEBUG, "Maximum Associativity to test for is %d sets\n", (int)(workSize / minPage) ); /* Do the test for each detected tlb in the system */ if( sys.dataTLB ) { show( VERB_NORMAL, "Data TLB:\n" ); show(VERB_PLOT,"# PLOT using 6:2 title \"Data TLB Associativity \" \n"); error = tlbAssocRun( sys.array, workSize, minPage, TYPE_DATA ); } if( sys.instTLB ) { show( VERB_NORMAL, "Instruction TLB:\n" ); show(VERB_PLOT,"\n\n# PLOT using 6:2 title \"Instruction TLB Associativity \" \n"); error += tlbAssocRun( sys.array, workSize, minPage,TYPE_INST ); } show(VERB_PLOT,"\n\n");/* Separate the sets of the output data file */ return( error ); } static int tlbAssocRun( char *array, unsigned int maxMem, unsigned int minPage, type_t type ) { double * access, * control; int * assocs; unsigned int i, j, trial, assoc, selected; struct tlb ** tlb; access = (double *)calloc( (unsigned int)(maxMem/minPage)/2, sizeof(double) ); control = (double *)calloc( (unsigned int)(maxMem/minPage)/2, sizeof(double) ); assocs = (int *)calloc( (unsigned int)(maxMem/minPage)/2 , sizeof(int) ); if( access == NULL || control == NULL ) handleError( "getting access array in tlbAssocRun", EnoMem ); /* take the minimum of a number of runs */ for( trial = 1; trial <= sys.args.trials; trial++ ){ /* perform the benchmark for different number of jumps of minPage */ for( assoc = 2, i = 1; assoc<16; assoc++ ){ if( trial == 1 ){ access[i] = (double)LONG_MAX; control[i] = (double)LONG_MAX; } /* perform benchmark access */ access[i] = min( access[i], tlbAssocAccess( array, assoc, minPage, type ) ); control[i] = min( control[i], tlbAssocCtrl( array, assoc, minPage, type ) ); assocs[i]= assoc; if( trial == sys.args.trials ){ show( VERB_INSPECT, "Time: %.4f ns %.4f ns [assoc %d ]\n", access[i],control[i],assoc-1); show( VERB_PLOT, "Time: %.4f ns [ assoc %d ]\n", access[i],assoc-1); } } /* Test with lower resolution (16) after we break the 16 barrier */ for( assoc=32, j=1; assoc<=(maxMem/minPage); assoc=assoc+16,i++ ){ if( trial == 1 ){ access[i] = (double)LONG_MAX; control[i] = (double)LONG_MAX; } /* perform benchmark access */ access[i] = min( access[i], tlbAssocAccess( array, assoc, minPage, type ) ); control[i] = min( control[i], tlbAssocCtrl( array, assoc, minPage, type ) ); assocs[i]= assoc; if( trial == sys.args.trials ){ show( VERB_INSPECT, "Time: %.4f ns %.4f ns [assoc %d ]\n", access[i],control[i],assoc-16); show( VERB_PLOT, "Time: %.4f ns [ assoc %d ]\n", access[i],assoc-16); } } } selected = getFirstTransition( access, control, i ); if( selected < 1 ){ show(VERB_NORMAL," None selected...\n"); return( selected ); } /* if we selected the las transition, we cannot test for intermediate points, so that's our best guess...*/ show(VERB_DEBUG, "SELECTED: %d [Assoc: %d ]\n",selected,assocs[selected]); /* Write result in the tlb structure */ if( type == TYPE_DATA ) tlb=&sys.dataTLB; else tlb=&sys.instTLB; (*tlb)->associativity = assocs[selected]; show(VERB_NORMAL,"Found associativity %u \n", (*tlb)->associativity ); free( access ); free( control ); free( assocs ); return( 0 ); } /* Run tlb associativity benchmark for data or instruction tlbs. array - memory to access assoc - associativity to test stride - page size to stride type - type of cache to benchmark return - result of benchmark of trial */ static double tlbAssocAccess( char *array, unsigned int assoc, unsigned int stride, type_t type ) { unsigned int size; double result; /* calculate the size of memory to cover */ size = assoc * stride; /* perform the appropriate benchmark test */ if( type == TYPE_DATA ) result = dataReadWrap( array, size, stride, MIN_SETS ); else result = instExecute( array, size, stride, MIN_SETS ); /* return the average result per operation in ns */ return( result ); } /* Run tlb control times for associativity benchmark. array - memory to "cover" assoc - associativity to test stride - page size to stride type - type of cache to benchmark return - result of benchmark of trial */ static double tlbAssocCtrl( char *array, unsigned int assoc, unsigned int stride, type_t type ) { unsigned int size; double result; /* calculate the size of memory to cover */ size = assoc * stride; /* perform the appropriate benchmark test */ if( type == TYPE_DATA ) result = ctrlReadWrap( array, size, stride, MIN_SETS ); else /* For instructions we will use associativity of 1 as the control time since we want to have comparable times as well as noise measurement and ctrlReadWrap is too fast to be compared with instruction times...*/ result = instExecute( array, stride, stride, MIN_SETS ); /* return the average result per operation in ns */ return( result ); } /* We'll return a 1 (valid) if we find that both TLB's are allocated and have a non-zero associativity value. return - 1 if valid, 0 otherwise */ int tlbAssocValid( void ) { if( sys.dataTLB && sys.instTLB && sys.dataTLB->associativity && sys.instTLB->associativity ) return 1; /* Assume valid if we have them both with non undefined value */ return( 0 ); }