#include #include #include // // - hStartOfRace is a manual reset event that is signalled when // all of the threads are supposed to cut loose and begin working // // - hEndOfRace is a manual reset event that is signalled once the end time // has been retrieved and it is ok for the threads to exit // HANDLE hStartOfRace; HANDLE hEndOfRace; #define MAX_THREADS 32 // // - ThreadReadyDoneEvents are an array of autoclearing events. The threads // initially signal these events once they have reached their start routines // and are ready to being processing. Once they are done processing, they // signal thier event to indicate that they are done processing. // // - ThreadHandles are an array of thread handles to the worker threads. The // main thread waits on these to know when all of the threads have exited. // HANDLE ThreadReadyDoneEvents[MAX_THREADS]; HANDLE ThreadHandles[MAX_THREADS]; // // Each thread has a THREAD_WORK structure. This contains the address // of the cells that this thread is responsible for, and the number of // cells it is supposed to process. // typedef struct _THREAD_WORK { PDWORD CellVector; DWORD NumberOfCells; DWORD RecalcResult; } THREAD_WORK, *PTHREAD_WORK; THREAD_WORK ThreadWork[MAX_THREADS]; #define ONE_MB (1024*1024) DWORD Mb = 4; DWORD NumberOfThreads = 1; DWORD ExpectedRecalcValue; DWORD ActualRecalcValue; DWORD ContentionValue; BOOL fMemoryContention; DWORD WorkerThread(PVOID ThreadIndex); int __cdecl main( int argc, char *argv[], char *envp[] ) { DWORD StartTicks, EndTicks; DWORD i; BOOL fShowUsage; char c, *p, *whocares; PDWORD CellVector; DWORD NumberOfDwords; DWORD DwordsPerThread; DWORD ThreadId; LPSTR Answer; fShowUsage = FALSE; fMemoryContention = FALSE; if (argc <= 1) { goto showUsage; } while (--argc) { p = *++argv; if (*p == '/' || *p == '-') { while (c = *++p) switch (toupper( c )) { case '?': fShowUsage = TRUE; goto showUsage; break; case 'M': if (!argc--) { fShowUsage = TRUE; goto showUsage; } argv++; Mb = strtoul(*argv,&whocares,10); break; case 'C': fMemoryContention = TRUE; break; case 'T': if (!argc--) { fShowUsage = TRUE; goto showUsage; } argv++; NumberOfThreads = strtoul(*argv,&whocares,10); if ( NumberOfThreads > MAX_THREADS ) { fShowUsage = TRUE; goto showUsage; } break; default: fprintf( stderr, "MTBNCH: Invalid switch - /%c\n", c ); goto showUsage; break; } } } showUsage: if ( fShowUsage ) { fprintf(stderr,"usage: MTBNCH\n" ); fprintf(stderr," [-?] display this message\n" ); fprintf(stderr," [-t n] use n threads for benchmark (less than 32)\n" ); fprintf(stderr," [-m n] use an n Mb spreadsheet size (default 4)\n" ); fprintf(stderr," [-c] cause memory contention on each loop iteration\n" ); ExitProcess(1); } // // Prepare the race events. These are manual reset events. // hStartOfRace = CreateEvent(NULL,TRUE,FALSE,NULL); hEndOfRace = CreateEvent(NULL,TRUE,FALSE,NULL); if ( !hStartOfRace || !hEndOfRace ) { fprintf(stderr,"MTBNCH: Race Event Creation Failed\n"); ExitProcess(1); } // // Prepare the ready done events. These are auto clearing events // for(i=0; i