2016-04-24 20:07:46 -04:00
/*
* test - trans . c - Checks the correctness and performance of all of the
* student ' s transpose functions and records the results for their
* official submitted version as well .
*/
# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
# include <unistd.h>
# include <string.h>
# include <signal.h>
# include <getopt.h>
# include <sys/types.h>
# include "cachelab.h"
# include <sys/wait.h> // fir WEXITSTATUS
# include <limits.h> // for INT_MAX
/* Maximum array dimension */
# define MAXN 256
/* The description string for the transpose_submit() function that the
student submits for credit */
# define SUBMIT_DESCRIPTION "Transpose submission"
/* External function defined in trans.c */
extern void registerFunctions ( ) ;
/* External variables defined in cachelab-tools.c */
extern trans_func_t func_list [ MAX_TRANS_FUNCS ] ;
2016-04-24 20:12:20 -04:00
extern int func_counter ;
2016-04-24 20:07:46 -04:00
/* Globals set on the command line */
static int M = 0 ;
static int N = 0 ;
/* The correctness and performance for the submitted transpose function */
struct results {
int funcid ;
int correct ;
int misses ;
} ;
static struct results results = { - 1 , 0 , INT_MAX } ;
2016-04-24 20:12:20 -04:00
/*
2016-04-24 20:07:46 -04:00
* eval_perf - Evaluate the performance of the registered transpose functions
*/
void eval_perf ( unsigned int s , unsigned int E , unsigned int b )
{
int i , flag ;
unsigned int len , hits , misses , evictions ;
unsigned long long int marker_start , marker_end , addr ;
char buf [ 1000 ] , cmd [ 255 ] ;
char filename [ 128 ] ;
2016-04-24 20:12:20 -04:00
registerFunctions ( ) ;
2016-04-24 20:07:46 -04:00
/* Open the complete trace file */
2016-04-24 20:12:20 -04:00
FILE * full_trace_fp ;
FILE * part_trace_fp ;
2016-04-24 20:07:46 -04:00
/* Evaluate the performance of each registered transpose function */
for ( i = 0 ; i < func_counter ; i + + ) {
if ( strcmp ( func_list [ i ] . description , SUBMIT_DESCRIPTION ) = = 0 )
results . funcid = i ; /* remember which function is the submission */
printf ( " \n Function %d (%d total) \n Step 1: Validating and generating memory traces \n " , i , func_counter ) ;
/* Use valgrind to generate the trace */
sprintf ( cmd , " valgrind --tool=lackey --trace-mem=yes --log-fd=1 -v ./tracegen -M %d -N %d -F %d > trace.tmp " , M , N , i ) ;
flag = WEXITSTATUS ( system ( cmd ) ) ;
if ( 0 ! = flag ) {
2016-04-24 20:12:20 -04:00
printf ( " Validation error at function %d! Run ./tracegen -M %d -N %d -F %d for details. \n Skipping performance evaluation for this function. \n " , flag - 1 , M , N , i ) ;
2016-04-24 20:07:46 -04:00
continue ;
}
/* Get the start and end marker addresses */
FILE * marker_fp = fopen ( " .marker " , " r " ) ;
assert ( marker_fp ) ;
fscanf ( marker_fp , " %llx %llx " , & marker_start , & marker_end ) ;
fclose ( marker_fp ) ;
func_list [ i ] . correct = 1 ;
/* Save the correctness of the transpose submission */
if ( results . funcid = = i ) {
results . correct = 1 ;
}
full_trace_fp = fopen ( " trace.tmp " , " r " ) ;
assert ( full_trace_fp ) ;
/* Filtered trace for each transpose function goes in a separate file */
sprintf ( filename , " trace.f%d " , i ) ;
part_trace_fp = fopen ( filename , " w " ) ;
assert ( part_trace_fp ) ;
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
/* Locate trace corresponding to the trans function */
flag = 0 ;
while ( fgets ( buf , 1000 , full_trace_fp ) ! = NULL ) {
/* We are only interested in memory access instructions */
if ( buf [ 0 ] = = ' ' & & buf [ 2 ] = = ' ' & &
( buf [ 1 ] = = ' S ' | | buf [ 1 ] = = ' M ' | | buf [ 1 ] = = ' L ' ) ) {
sscanf ( buf + 3 , " %llx,%u " , & addr , & len ) ;
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
/* If start marker found, set flag */
if ( addr = = marker_start )
flag = 1 ;
/* Valgrind creates many spurious accesses to the
stack that have nothing to do with the students
code . At the moment , we are ignoring all stack
accesses by using the simple filter of recording
accesses to only the low 32 - bit portion of the
address space . At some point it would be nice to
try to do more informed filtering so that would
eliminate the valgrind stack references while
include the student stack references . */
if ( flag & & addr < 0xffffffff ) {
fputs ( buf , part_trace_fp ) ;
}
/* if end marker found, close trace file */
if ( addr = = marker_end ) {
flag = 0 ;
fclose ( part_trace_fp ) ;
break ;
}
}
}
fclose ( full_trace_fp ) ;
/* Run the reference simulator */
printf ( " Step 2: Evaluating performance (s=%d, E=%d, b=%d) \n " , s , E , b ) ;
char cmd [ 255 ] ;
2016-04-24 20:12:20 -04:00
sprintf ( cmd , " ./csim-ref -s %u -E %u -b %u -t trace.f%d > /dev/null " ,
2016-04-24 20:07:46 -04:00
s , E , b , i ) ;
system ( cmd ) ;
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
/* Collect results from the reference simulator */
FILE * in_fp = fopen ( " .csim_results " , " r " ) ;
assert ( in_fp ) ;
fscanf ( in_fp , " %u %u %u " , & hits , & misses , & evictions ) ;
fclose ( in_fp ) ;
func_list [ i ] . num_hits = hits ;
func_list [ i ] . num_misses = misses ;
func_list [ i ] . num_evictions = evictions ;
printf ( " func %u (%s): hits:%u, misses:%u, evictions:%u \n " ,
i , func_list [ i ] . description , hits , misses , evictions ) ;
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
/* If it is transpose_submit(), record number of misses */
if ( results . funcid = = i ) {
results . misses = misses ;
}
}
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
}
/*
* usage - Print usage info
*/
void usage ( char * argv [ ] ) {
printf ( " Usage: %s [-h] -M <rows> -N <cols> \n " , argv [ 0 ] ) ;
printf ( " Options: \n " ) ;
printf ( " -h Print this help message. \n " ) ;
printf ( " -M <rows> Number of matrix rows (max %d) \n " , MAXN ) ;
printf ( " -N <cols> Number of matrix columns (max %d) \n " , MAXN ) ;
2016-04-24 20:12:20 -04:00
printf ( " Example: %s -M 8 -N 8 \n " , argv [ 0 ] ) ;
2016-04-24 20:07:46 -04:00
}
/*
* sigsegv_handler - SIGSEGV handler
*/
void sigsegv_handler ( int signum ) {
printf ( " Error: Segmentation Fault. \n " ) ;
printf ( " TEST_TRANS_RESULTS=0:0 \n " ) ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
/*
* sigalrm_handler - SIGALRM handler
*/
void sigalrm_handler ( int signum ) {
printf ( " Error: Program timed out. \n " ) ;
printf ( " TEST_TRANS_RESULTS=0:0 \n " ) ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
2016-04-24 20:12:20 -04:00
/*
2016-04-24 20:07:46 -04:00
* main - Main routine
*/
int main ( int argc , char * argv [ ] )
{
char c ;
while ( ( c = getopt ( argc , argv , " M:N:h " ) ) ! = - 1 ) {
switch ( c ) {
case ' M ' :
M = atoi ( optarg ) ;
break ;
case ' N ' :
N = atoi ( optarg ) ;
break ;
case ' h ' :
usage ( argv ) ;
exit ( 0 ) ;
default :
usage ( argv ) ;
exit ( 1 ) ;
}
}
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
if ( M = = 0 | | N = = 0 ) {
printf ( " Error: Missing required argument \n " ) ;
usage ( argv ) ;
exit ( 1 ) ;
}
if ( M > MAXN | | N > MAXN ) {
printf ( " Error: M or N exceeds %d \n " , MAXN ) ;
usage ( argv ) ;
exit ( 1 ) ;
}
/* Install SIGSEGV and SIGALRM handlers */
if ( signal ( SIGSEGV , sigsegv_handler ) = = SIG_ERR ) {
fprintf ( stderr , " Unable to install SIGALRM handler \n " ) ;
exit ( 1 ) ;
}
if ( signal ( SIGALRM , sigalrm_handler ) = = SIG_ERR ) {
fprintf ( stderr , " Unable to install SIGALRM handler \n " ) ;
exit ( 1 ) ;
}
/* Time out and give up after a while */
alarm ( 120 ) ;
/* Check the performance of the student's transpose function */
eval_perf ( 5 , 1 , 5 ) ;
2016-04-24 20:12:20 -04:00
2016-04-24 20:07:46 -04:00
/* Emit the results for this particular test */
if ( results . funcid = = - 1 ) {
printf ( " \n Error: We could not find your transpose_submit() function \n " ) ;
2016-04-24 20:12:20 -04:00
printf ( " Error: Please ensure that description field is exactly \" %s \" \n " ,
2016-04-24 20:07:46 -04:00
SUBMIT_DESCRIPTION ) ;
printf ( " \n TEST_TRANS_RESULTS=0:0 \n " ) ;
}
else {
printf ( " \n Summary for official submission (func %d): correctness=%d misses=%d \n " ,
results . funcid , results . correct , results . misses ) ;
printf ( " \n TEST_TRANS_RESULTS=%d:%d \n " , results . correct , results . misses ) ;
}
return 0 ;
}