#include #include #include #include BOOL fShowScaling; #define MAX_THREADS 32 // // - 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; // // - 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]; DWORD WorkerThread(PVOID ThreadIndex); DWORD ThreadId; DWORD StartTicks, EndTicks; HANDLE IoHandle; #define SIXTY_FOUR_K (64*1024) #define SIXTEEN_K (16*1024) unsigned int InitialBuffer[SIXTY_FOUR_K/sizeof(unsigned int)]; #define NUMBER_OF_WRITES ((1024*1024*8)/SIXTY_FOUR_K) #define BUFFER_MAX (64*1024) #define FILE_SIZE ((1024*1024*8)-BUFFER_MAX) /* // 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 { unsigned long *CellVector; int NumberOfCells; int RecalcResult; BOOL GlobalMode; } THREAD_WORK, *PTHREAD_WORK; unsigned int GlobalData[MAX_THREADS]; THREAD_WORK ThreadWork[MAX_THREADS]; #define ONE_MB (1024*1024) unsigned long Mb = 16; unsigned long ExpectedRecalcValue; unsigned long ActualRecalcValue; unsigned long ContentionValue; int fGlobalMode; int WorkIndex; int BufferSize; unsigned long *CellVector; DWORD DoAnInteration( int NumberOfThreads, BOOL GlobalMode ) { int i; int fShowUsage; char c, *p, *whocares; int NumberOfDwords; int CNumberOfDwords; int DwordsPerThread; char *Answer; unsigned long x; fGlobalMode = 0; BufferSize = 1024; hStartOfRace = CreateEvent(NULL,TRUE,FALSE,NULL); hEndOfRace = CreateEvent(NULL,TRUE,FALSE,NULL); if ( !hStartOfRace || !hEndOfRace ) { fprintf(stderr,"SMPSCALE Race Event Creation Failed\n"); ExitProcess(1); } /* // Prepare the ready done events. These are auto clearing events */ for(i=0; i 1 ) { fShowScaling = TRUE; } else { fShowScaling = FALSE; } CellVector = (PDWORD)VirtualAlloc(NULL,Mb*ONE_MB,MEM_COMMIT,PAGE_READWRITE); if ( !CellVector ) { fprintf(stderr,"SMPSCALE Cell Vector Allocation Failed %d\n",GetLastError()); ExitProcess(1); } BaseLine = DoAnInteration(1,FALSE); i = 0; while(i++<10) { Time = DoAnInteration(1,FALSE); if ( Time == BaseLine ) { break; } if ( abs(Time-BaseLine) < 2 ) { break; } BaseLine = Time; } GetSystemInfo(&SystemInfo); fprintf(stdout,"%d Processor System. Single Processor BaseLine %dms\n\n", SystemInfo.dwNumberOfProcessors, BaseLine ); if ( !fShowScaling ) { fprintf(stdout," Time Time with Cache Sloshing\n"); } for ( i=0;i 0 ) { fprintf(stdout,"%1d Processors %4dms (%3d%%) %4dms (%3d%%) (with cache contention)\n", i+1,Time,((BaseLine*100)/Time-100),GlobalModeTime,((BaseLine*100)/GlobalModeTime-100) ); } else { fprintf(stdout,"%1d Processors %4dms %4dms (with cache contention)\n", i+1,Time,GlobalModeTime ); } } else { fprintf(stdout,"%1d Processors %4dms vs %4dms\n", i+1,Time,GlobalModeTime ); } } ExitProcess(2); } /* // The worker threads perform the recalc operation on their // assigned cells. They begin by setting their ready done event // to indicate that they are ready to begin the recalc. Then they // wait until the hStartOfRace event is signaled. Once this occurs, they // do their part of the recalc and when done they signal their ready done // event and then wait on the hEndOfRaceEvent */ DWORD WorkerThread( PVOID ThreadIndex ) { unsigned long Me; unsigned long *MyCellVectorBase; unsigned long *CurrentCellVector; unsigned long MyRecalcValue; unsigned long MyNumberOfCells; unsigned long i,j; int GlobalMode; HANDLE hEvent; BOOL b; Me = (unsigned long)ThreadIndex; MyRecalcValue = 0; MyCellVectorBase = ThreadWork[Me].CellVector; MyNumberOfCells = ThreadWork[Me].NumberOfCells; GlobalMode = ThreadWork[Me].GlobalMode; /* // Signal that I am ready to go */ if ( !SetEvent(ThreadReadyDoneEvents[Me]) ) { fprintf(stderr,"SMPSCALE (1) SetEvent(ThreadReadyDoneEvent[%d]) Failed %d\n",Me,GetLastError()); ExitProcess(1); } /* // Wait for the master to release us to do the recalc */ i = WaitForSingleObject(hStartOfRace,INFINITE); if ( i == WAIT_FAILED ) { fprintf(stderr,"SMPSCALE Thread %d Wait for start of recalc Failed %d\n",Me,GetLastError()); ExitProcess(1); } /* // perform the recalc operation */ for (i=0, CurrentCellVector = MyCellVectorBase,j=0; i