Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

397 lines
11 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. BOOL fShowScaling;
  6. #define MAX_THREADS 32
  7. //
  8. // - hStartOfRace is a manual reset event that is signalled when
  9. // all of the threads are supposed to cut loose and begin working
  10. //
  11. // - hEndOfRace is a manual reset event that is signalled once the end time
  12. // has been retrieved and it is ok for the threads to exit
  13. //
  14. HANDLE hStartOfRace;
  15. HANDLE hEndOfRace;
  16. //
  17. // - ThreadReadyDoneEvents are an array of autoclearing events. The threads
  18. // initially signal these events once they have reached their start routines
  19. // and are ready to being processing. Once they are done processing, they
  20. // signal thier event to indicate that they are done processing.
  21. //
  22. // - ThreadHandles are an array of thread handles to the worker threads. The
  23. // main thread waits on these to know when all of the threads have exited.
  24. //
  25. HANDLE ThreadReadyDoneEvents[MAX_THREADS];
  26. HANDLE ThreadHandles[MAX_THREADS];
  27. DWORD WorkerThread(PVOID ThreadIndex);
  28. DWORD ThreadId;
  29. DWORD StartTicks, EndTicks;
  30. HANDLE IoHandle;
  31. #define SIXTY_FOUR_K (64*1024)
  32. #define SIXTEEN_K (16*1024)
  33. unsigned int InitialBuffer[SIXTY_FOUR_K/sizeof(unsigned int)];
  34. #define NUMBER_OF_WRITES ((1024*1024*8)/SIXTY_FOUR_K)
  35. #define BUFFER_MAX (64*1024)
  36. #define FILE_SIZE ((1024*1024*8)-BUFFER_MAX)
  37. /*
  38. // Each thread has a THREAD_WORK structure. This contains the address
  39. // of the cells that this thread is responsible for, and the number of
  40. // cells it is supposed to process.
  41. */
  42. typedef struct _THREAD_WORK {
  43. unsigned long *CellVector;
  44. int NumberOfCells;
  45. int RecalcResult;
  46. BOOL GlobalMode;
  47. } THREAD_WORK, *PTHREAD_WORK;
  48. unsigned int GlobalData[MAX_THREADS];
  49. THREAD_WORK ThreadWork[MAX_THREADS];
  50. #define ONE_MB (1024*1024)
  51. unsigned long Mb = 16;
  52. unsigned long ExpectedRecalcValue;
  53. unsigned long ActualRecalcValue;
  54. unsigned long ContentionValue;
  55. int fGlobalMode;
  56. int WorkIndex;
  57. int BufferSize;
  58. unsigned long *CellVector;
  59. DWORD
  60. DoAnInteration(
  61. int NumberOfThreads,
  62. BOOL GlobalMode
  63. )
  64. {
  65. int i;
  66. int fShowUsage;
  67. char c, *p, *whocares;
  68. int NumberOfDwords;
  69. int CNumberOfDwords;
  70. int DwordsPerThread;
  71. char *Answer;
  72. unsigned long x;
  73. fGlobalMode = 0;
  74. BufferSize = 1024;
  75. hStartOfRace = CreateEvent(NULL,TRUE,FALSE,NULL);
  76. hEndOfRace = CreateEvent(NULL,TRUE,FALSE,NULL);
  77. if ( !hStartOfRace || !hEndOfRace ) {
  78. fprintf(stderr,"SMPSCALE Race Event Creation Failed\n");
  79. ExitProcess(1);
  80. }
  81. /*
  82. // Prepare the ready done events. These are auto clearing events
  83. */
  84. for(i=0; i<NumberOfThreads; i++ ) {
  85. ThreadReadyDoneEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL);
  86. if ( !ThreadReadyDoneEvents[i] ) {
  87. fprintf(stderr,"SMPSCALE Ready Done Event Creation Failed %d\n",GetLastError());
  88. ExitProcess(1);
  89. }
  90. }
  91. NumberOfDwords = (Mb*ONE_MB) / sizeof(unsigned long);
  92. CNumberOfDwords = NumberOfDwords;
  93. DwordsPerThread = NumberOfDwords / NumberOfThreads;
  94. /*
  95. // Initialize the Cell Vector
  96. */
  97. for(i=0, ExpectedRecalcValue=0; i<NumberOfDwords; i++ ){
  98. ExpectedRecalcValue += i;
  99. CellVector[i] = i;
  100. }
  101. /*
  102. // Partition the work to the worker threads
  103. */
  104. for(i=0; i<NumberOfThreads; i++ ){
  105. ThreadWork[i].CellVector = &CellVector[i*DwordsPerThread];
  106. ThreadWork[i].NumberOfCells = DwordsPerThread;
  107. NumberOfDwords -= DwordsPerThread;
  108. /*
  109. // If we have a remainder, give the remaining work to the last thread
  110. */
  111. if ( NumberOfDwords < DwordsPerThread ) {
  112. ThreadWork[i].NumberOfCells += NumberOfDwords;
  113. }
  114. }
  115. /*
  116. // Create the worker threads
  117. */
  118. for(i=0; i<NumberOfThreads; i++ ) {
  119. ThreadWork[i].RecalcResult = 0;
  120. ThreadWork[i].GlobalMode = GlobalMode;
  121. GlobalData[i] = 0;
  122. ThreadHandles[i] = CreateThread(
  123. NULL,
  124. 0,
  125. WorkerThread,
  126. (PVOID)i,
  127. 0,
  128. &ThreadId
  129. );
  130. if ( !ThreadHandles[i] ) {
  131. fprintf(stderr,"SMPSCALE Worker Thread Creation Failed %d\n",GetLastError());
  132. ExitProcess(1);
  133. }
  134. CloseHandle(ThreadHandles[i]);
  135. }
  136. /*
  137. // All of the worker threads will signal thier ready done event
  138. // when they are idle and ready to proceed. Once all events have been
  139. // set, then setting the hStartOfRaceEvent will begin the recalc
  140. */
  141. i = WaitForMultipleObjects(
  142. NumberOfThreads,
  143. ThreadReadyDoneEvents,
  144. TRUE,
  145. INFINITE
  146. );
  147. if ( i == WAIT_FAILED ) {
  148. fprintf(stderr,"SMPSCALE Wait for threads to stabalize Failed %d\n",GetLastError());
  149. ExitProcess(1);
  150. }
  151. /*
  152. // Everthing is set to begin the recalc operation
  153. */
  154. StartTicks = GetTickCount();
  155. if ( !SetEvent(hStartOfRace) ) {
  156. fprintf(stderr,"SMPSCALE SetEvent(hStartOfRace) Failed %d\n",GetLastError());
  157. ExitProcess(1);
  158. }
  159. /*
  160. // Now just wait for the recalc to complete
  161. */
  162. i = WaitForMultipleObjects(
  163. NumberOfThreads,
  164. ThreadReadyDoneEvents,
  165. TRUE,
  166. INFINITE
  167. );
  168. if ( i == WAIT_FAILED ) {
  169. fprintf(stderr,"SMPSCALE Wait for threads to complete Failed %d\n",GetLastError());
  170. ExitProcess(1);
  171. }
  172. /*
  173. // Now pick up the individual recalc values
  174. */
  175. for(i=0, ActualRecalcValue = 0; i<NumberOfThreads; i++ ){
  176. ActualRecalcValue += ThreadWork[i].RecalcResult;
  177. }
  178. EndTicks = GetTickCount();
  179. if ( ActualRecalcValue != ExpectedRecalcValue ) {
  180. fprintf(stderr,"SMPSCALE Recalc Failuer !\n");
  181. ExitProcess(1);
  182. }
  183. return (EndTicks - StartTicks);
  184. }
  185. int __cdecl
  186. main(
  187. int argc,
  188. char *argv[],
  189. char *envp[]
  190. )
  191. {
  192. DWORD Time,GlobalModeTime;
  193. DWORD BaseLine;
  194. DWORD i;
  195. SYSTEM_INFO SystemInfo;
  196. /*
  197. // Allocate and initialize the CellVector
  198. */
  199. if ( argc > 1 ) {
  200. fShowScaling = TRUE;
  201. }
  202. else {
  203. fShowScaling = FALSE;
  204. }
  205. CellVector = (PDWORD)VirtualAlloc(NULL,Mb*ONE_MB,MEM_COMMIT,PAGE_READWRITE);
  206. if ( !CellVector ) {
  207. fprintf(stderr,"SMPSCALE Cell Vector Allocation Failed %d\n",GetLastError());
  208. ExitProcess(1);
  209. }
  210. BaseLine = DoAnInteration(1,FALSE);
  211. i = 0;
  212. while(i++<10) {
  213. Time = DoAnInteration(1,FALSE);
  214. if ( Time == BaseLine ) {
  215. break;
  216. }
  217. if ( abs(Time-BaseLine) < 2 ) {
  218. break;
  219. }
  220. BaseLine = Time;
  221. }
  222. GetSystemInfo(&SystemInfo);
  223. fprintf(stdout,"%d Processor System. Single Processor BaseLine %dms\n\n",
  224. SystemInfo.dwNumberOfProcessors,
  225. BaseLine
  226. );
  227. if ( !fShowScaling ) {
  228. fprintf(stdout," Time Time with Cache Sloshing\n");
  229. }
  230. for ( i=0;i<SystemInfo.dwNumberOfProcessors;i++) {
  231. Time = DoAnInteration(i+1,FALSE);
  232. GlobalModeTime = DoAnInteration(i+1,TRUE);
  233. if ( fShowScaling ) {
  234. if ( i > 0 ) {
  235. fprintf(stdout,"%1d Processors %4dms (%3d%%) %4dms (%3d%%) (with cache contention)\n",
  236. i+1,Time,((BaseLine*100)/Time-100),GlobalModeTime,((BaseLine*100)/GlobalModeTime-100)
  237. );
  238. }
  239. else {
  240. fprintf(stdout,"%1d Processors %4dms %4dms (with cache contention)\n",
  241. i+1,Time,GlobalModeTime
  242. );
  243. }
  244. }
  245. else {
  246. fprintf(stdout,"%1d Processors %4dms vs %4dms\n",
  247. i+1,Time,GlobalModeTime
  248. );
  249. }
  250. }
  251. ExitProcess(2);
  252. }
  253. /*
  254. // The worker threads perform the recalc operation on their
  255. // assigned cells. They begin by setting their ready done event
  256. // to indicate that they are ready to begin the recalc. Then they
  257. // wait until the hStartOfRace event is signaled. Once this occurs, they
  258. // do their part of the recalc and when done they signal their ready done
  259. // event and then wait on the hEndOfRaceEvent
  260. */
  261. DWORD
  262. WorkerThread(
  263. PVOID ThreadIndex
  264. )
  265. {
  266. unsigned long Me;
  267. unsigned long *MyCellVectorBase;
  268. unsigned long *CurrentCellVector;
  269. unsigned long MyRecalcValue;
  270. unsigned long MyNumberOfCells;
  271. unsigned long i,j;
  272. int GlobalMode;
  273. HANDLE hEvent;
  274. BOOL b;
  275. Me = (unsigned long)ThreadIndex;
  276. MyRecalcValue = 0;
  277. MyCellVectorBase = ThreadWork[Me].CellVector;
  278. MyNumberOfCells = ThreadWork[Me].NumberOfCells;
  279. GlobalMode = ThreadWork[Me].GlobalMode;
  280. /*
  281. // Signal that I am ready to go
  282. */
  283. if ( !SetEvent(ThreadReadyDoneEvents[Me]) ) {
  284. fprintf(stderr,"SMPSCALE (1) SetEvent(ThreadReadyDoneEvent[%d]) Failed %d\n",Me,GetLastError());
  285. ExitProcess(1);
  286. }
  287. /*
  288. // Wait for the master to release us to do the recalc
  289. */
  290. i = WaitForSingleObject(hStartOfRace,INFINITE);
  291. if ( i == WAIT_FAILED ) {
  292. fprintf(stderr,"SMPSCALE Thread %d Wait for start of recalc Failed %d\n",Me,GetLastError());
  293. ExitProcess(1);
  294. }
  295. /*
  296. // perform the recalc operation
  297. */
  298. for (i=0, CurrentCellVector = MyCellVectorBase,j=0; i<MyNumberOfCells; i++ ) {
  299. if (GlobalMode){
  300. GlobalData[Me] += *CurrentCellVector++;
  301. }
  302. else {
  303. MyRecalcValue += *CurrentCellVector++;
  304. }
  305. }
  306. if (GlobalMode){
  307. MyRecalcValue = GlobalData[Me];
  308. }
  309. ThreadWork[Me].RecalcResult = MyRecalcValue;
  310. /*
  311. // Signal that I am done and then wait for further instructions
  312. */
  313. if ( !SetEvent(ThreadReadyDoneEvents[Me]) ) {
  314. fprintf(stderr,"SMPSCALE (2) SetEvent(ThreadReadyDoneEvent[%d]) Failed %d\n",Me,GetLastError());
  315. ExitProcess(1);
  316. }
  317. i = WaitForSingleObject(hEndOfRace,INFINITE);
  318. if ( i == WAIT_FAILED ) {
  319. fprintf(stderr,"SMPSCALE Thread %d Wait for end of recalc Failed %d\n",Me,GetLastError());
  320. ExitProcess(1);
  321. }
  322. return MyRecalcValue;
  323. }