Source code of Windows XP (NT5)
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.

380 lines
8.7 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <ctype.h>
  5. //
  6. // Unbuffered write test
  7. //
  8. #define TEST_REPEAT_COUNT 10
  9. //
  10. // File is 20mb
  11. //
  12. #define BUFFER_SIZE (64*1024)
  13. #define NUMBER_OF_WRITES (320*1)
  14. int BufferSize;
  15. int NumberOfWrites;
  16. char *Buffer;
  17. BOOL fSequentialNew;
  18. BOOL fBufferdIo;
  19. BOOL fRaw;
  20. BOOL fWrite = TRUE;
  21. LPSTR FileName;
  22. VOID
  23. ParseSwitch(
  24. CHAR chSwitch,
  25. int *pArgc,
  26. char **pArgv[]
  27. );
  28. VOID
  29. ShowUsage(
  30. VOID
  31. );
  32. int
  33. __cdecl
  34. main(
  35. int argc,
  36. char *argv[],
  37. char *envp
  38. )
  39. {
  40. DWORD Start[TEST_REPEAT_COUNT];
  41. DWORD End[TEST_REPEAT_COUNT];
  42. DWORD Diff;
  43. double fDiff, fSec, fKb, fSumKbs;
  44. int TestNumber;
  45. HANDLE hFile, hPort;
  46. OVERLAPPED ov;
  47. LPOVERLAPPED ov2;
  48. int WriteCount;
  49. DWORD n,n2,key;
  50. BOOL b;
  51. int PendingIoCount;
  52. DWORD Version;
  53. DWORD FileFlags;
  54. char chChar, *pchChar;
  55. Version = GetVersion() >> 16;
  56. FileName = "unbufw.dat";
  57. fSequentialNew = FALSE;
  58. fBufferdIo = FALSE;
  59. fRaw = FALSE;
  60. BufferSize = BUFFER_SIZE;
  61. NumberOfWrites = ( (20*(1024*1024)) / BufferSize);
  62. while (--argc) {
  63. pchChar = *++argv;
  64. if (*pchChar == '/' || *pchChar == '-') {
  65. while (chChar = *++pchChar) {
  66. ParseSwitch( chChar, &argc, &argv );
  67. }
  68. }
  69. }
  70. if ( argc > 1 ) {
  71. FileName = argv[1];
  72. }
  73. else {
  74. }
  75. fSumKbs = 0.0;
  76. Buffer = VirtualAlloc(NULL,BUFFER_SIZE,MEM_COMMIT,PAGE_READWRITE);
  77. if ( !Buffer ) {
  78. printf("Error allocating buffer %d\n",GetLastError());
  79. return 99;
  80. }
  81. FileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
  82. if ( !fBufferdIo ) {
  83. FileFlags |= FILE_FLAG_NO_BUFFERING;
  84. }
  85. DeleteFile(FileName);
  86. for (TestNumber = 0; TestNumber < TEST_REPEAT_COUNT; TestNumber++ ) {
  87. hFile = CreateFile(
  88. FileName,
  89. GENERIC_READ | GENERIC_WRITE,
  90. FILE_SHARE_READ | FILE_SHARE_WRITE,
  91. NULL,
  92. fRaw ? OPEN_EXISTING : OPEN_ALWAYS,
  93. FileFlags,
  94. NULL
  95. );
  96. if ( hFile == INVALID_HANDLE_VALUE ) {
  97. printf("Error opening file %s %d\n",FileName,GetLastError());
  98. return 99;
  99. }
  100. hPort = CreateIoCompletionPort(
  101. hFile,
  102. NULL,
  103. (DWORD)hFile,
  104. 0
  105. );
  106. if ( !hPort ) {
  107. printf("Error creating completion port %d\n",FileName,GetLastError());
  108. return 99;
  109. }
  110. ZeroMemory(&ov,sizeof(ov));
  111. if ( TestNumber == 0 && fSequentialNew == FALSE) {
  112. Start[TestNumber] = GetTickCount();
  113. //
  114. // Make sure the file is written out to the end...
  115. //
  116. ov.Offset = (NUMBER_OF_WRITES * BUFFER_SIZE) - 1024;
  117. b = WriteFile(hFile,Buffer,1024,&n,&ov);
  118. if ( !b && GetLastError() != ERROR_IO_PENDING ) {
  119. printf("Error in pre-write %d\n",GetLastError());
  120. return 99;
  121. }
  122. b = GetQueuedCompletionStatus(
  123. hPort,
  124. &n2,
  125. &key,
  126. &ov2,
  127. (DWORD)-1
  128. );
  129. if ( !b ) {
  130. printf("Error picking up completion pre-write %d\n",GetLastError());
  131. return 99;
  132. }
  133. End[TestNumber] = GetTickCount();
  134. Diff = End[TestNumber] - Start[TestNumber];
  135. fDiff = Diff;
  136. fSec = fDiff/1000.0;
  137. fKb = ( (NumberOfWrites * BufferSize) / 1024 );
  138. printf("First Write %2dMb Written in %3.3fs I/O Rate %4.3f Kb/S\n\n",
  139. (NumberOfWrites * BufferSize) / ( 1024 * 1024),
  140. fSec,
  141. fKb / fSec
  142. );
  143. }
  144. ov.Offset = 0;
  145. PendingIoCount = 0;
  146. Start[TestNumber] = GetTickCount();
  147. //
  148. // Issue the writes
  149. //
  150. for (WriteCount = 0; WriteCount < NumberOfWrites; WriteCount++){
  151. reissuewrite:
  152. if ( fWrite ) {
  153. b = WriteFile(hFile,Buffer,BufferSize,&n,&ov);
  154. }
  155. else {
  156. b = ReadFile(hFile,Buffer,BufferSize,&n,&ov);
  157. }
  158. if ( !b && GetLastError() != ERROR_IO_PENDING ) {
  159. //
  160. // we reached our limit on outstanding I/Os
  161. //
  162. if ( GetLastError() == ERROR_INVALID_USER_BUFFER ||
  163. GetLastError() == ERROR_NOT_ENOUGH_QUOTA ||
  164. GetLastError() == ERROR_NOT_ENOUGH_MEMORY ) {
  165. //
  166. // wait for an outstanding I/O to complete and then go again
  167. //
  168. b = GetQueuedCompletionStatus(
  169. hPort,
  170. &n2,
  171. &key,
  172. &ov2,
  173. (DWORD)-1
  174. );
  175. if ( !b ) {
  176. printf("Error picking up completion write %d\n",GetLastError());
  177. return 99;
  178. }
  179. PendingIoCount--;
  180. goto reissuewrite;
  181. }
  182. else {
  183. printf("Error in write %d (pending count = %d)\n",GetLastError(),PendingIoCount);
  184. return 99;
  185. }
  186. }
  187. PendingIoCount++;
  188. ov.Offset += BufferSize;
  189. }
  190. //
  191. // Pick up the I/O completion
  192. //
  193. for (WriteCount = 0; WriteCount < PendingIoCount; WriteCount++){
  194. b = GetQueuedCompletionStatus(
  195. hPort,
  196. &n2,
  197. &key,
  198. &ov2,
  199. (DWORD)-1
  200. );
  201. if ( !b ) {
  202. printf("Error picking up completion write %d\n",GetLastError());
  203. return 99;
  204. }
  205. }
  206. End[TestNumber] = GetTickCount();
  207. CloseHandle(hFile);
  208. if ( Version > 613 ) {
  209. CloseHandle(hPort);
  210. }
  211. //
  212. // Dump the results
  213. //
  214. Diff = End[TestNumber] - Start[TestNumber];
  215. fDiff = Diff;
  216. fSec = fDiff/1000.0;
  217. fKb = ( (NumberOfWrites * BufferSize) / 1024 );
  218. printf("Test %2d %2dMb Written in %3.3fs I/O Rate %4.3f Kb/S\n",
  219. TestNumber,
  220. (NumberOfWrites * BufferSize) / ( 1024 * 1024),
  221. fSec,
  222. fKb / fSec
  223. );
  224. fSumKbs += (fKb / fSec);
  225. if ( fSequentialNew ) {
  226. DeleteFile(FileName);
  227. }
  228. }
  229. DeleteFile(FileName);
  230. //
  231. // Average
  232. //
  233. printf("\n Average Throughput %4.3f\n\n",
  234. fSumKbs/TEST_REPEAT_COUNT
  235. );
  236. }
  237. VOID
  238. ParseSwitch(
  239. CHAR chSwitch,
  240. int *pArgc,
  241. char **pArgv[]
  242. )
  243. {
  244. int bs;
  245. switch (toupper( chSwitch )) {
  246. case '?':
  247. ShowUsage();
  248. break;
  249. case 'F':
  250. if (!--(*pArgc)) {
  251. ShowUsage();
  252. }
  253. (*pArgv)++;
  254. FileName = *(*pArgv);
  255. break;
  256. case 'K':
  257. if (!--(*pArgc)) {
  258. ShowUsage();
  259. }
  260. (*pArgv)++;
  261. bs = strtoul( *(*pArgv), NULL, 10 );
  262. bs *= 1024;
  263. if ( bs > BUFFER_SIZE ) {
  264. ShowUsage();
  265. }
  266. BufferSize = bs;
  267. NumberOfWrites = ( (20*(1024*1024)) / BufferSize);
  268. break;
  269. case 'S':
  270. fSequentialNew = TRUE;
  271. break;
  272. case 'R':
  273. fRaw = TRUE;
  274. break;
  275. case 'B':
  276. fBufferdIo = TRUE;
  277. break;
  278. case 'X':
  279. fWrite = FALSE;
  280. break;
  281. default:
  282. fprintf( stderr, "UNBUFW: Invalid switch - /%c\n", chSwitch );
  283. ShowUsage();
  284. break;
  285. }
  286. }
  287. VOID
  288. ShowUsage(
  289. VOID
  290. )
  291. {
  292. fputs( "usage: UNBUFW [switches]\n"
  293. " [-f filename] supplies the output filename\n"
  294. " [-s] write sequentially without pre-allocating the file\n"
  295. " [-r] use raw I/O\n"
  296. " [-b] use buffered I/O instead of unbuffered I/O\n"
  297. " [-x] do reads instead of writes\n"
  298. " [-k write-size] use write-size k as write-size (64 is max)\n",
  299. stderr );
  300. exit( 1 );
  301. }