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.

1544 lines
41 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. yapt.c
  5. Abstract:
  6. This module contains the code for the Yet Another Performance Tool utility.
  7. Author:
  8. Chuck Park (chuckp) 07-Oct-1994
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <windowsx.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <time.h>
  21. #include <assert.h>
  22. #include "yapt.h"
  23. //
  24. // Test proc. declarations
  25. //
  26. BOOLEAN
  27. ReadSequential(
  28. ULONG Iterations
  29. );
  30. BOOLEAN
  31. WriteSequential(
  32. ULONG Iterations
  33. );
  34. BOOLEAN
  35. ReadRandom(
  36. ULONG Iterations
  37. );
  38. BOOLEAN
  39. WriteRandom(
  40. ULONG Iterations
  41. );
  42. //
  43. // Common util. functions
  44. //
  45. BOOLEAN
  46. CreateTestFile(
  47. );
  48. ULONG
  49. GetRandomOffset(
  50. ULONG min,
  51. ULONG max
  52. );
  53. BOOL
  54. GetSectorSize(
  55. PDWORD SectorSize,
  56. PCHAR DrvLetter
  57. );
  58. VOID
  59. LogError(
  60. PCHAR ErrString,
  61. DWORD UniqueId,
  62. DWORD ErrCode
  63. );
  64. BOOLEAN
  65. ParseCmdLine(
  66. INT Argc,
  67. CHAR *Argv[]
  68. );
  69. BOOLEAN
  70. ValidateOption(
  71. CHAR Switch,
  72. CHAR *Value
  73. );
  74. VOID
  75. VerifyFileName(
  76. IN CHAR *FileName
  77. );
  78. VOID
  79. Usage(
  80. VOID
  81. );
  82. VOID
  83. __cdecl
  84. Log(
  85. ULONG LogLevel,
  86. PCHAR String,
  87. ...
  88. );
  89. DWORD
  90. YaptSetFileCompression(
  91. IN HANDLE FileHandle,
  92. IN USHORT CompressionFormat
  93. );
  94. //
  95. // Default parameters
  96. //
  97. #define DEFAULT_BUFFER_SIZE 65536
  98. #define DEFAULT_FILE_SIZE (20*1024*1024);
  99. ULONG SectorSize = 512;
  100. ULONG BufferSize = DEFAULT_BUFFER_SIZE;
  101. ULONG FileSize = DEFAULT_FILE_SIZE;
  102. ULONG QueueSize = 0;
  103. UCHAR FileName[MAX_PATH] = "test.dat";
  104. UCHAR Test = READ;
  105. UCHAR Access = SEQ;
  106. ULONG Verbose = 0;
  107. ULONG Iterations = 10;
  108. UCHAR ReuseFile = TRUE;
  109. UCHAR Yes = FALSE;
  110. BOOLEAN ReadOnly = FALSE;
  111. INT
  112. _cdecl main (
  113. INT Argc,
  114. CHAR *Argv[]
  115. )
  116. {
  117. UCHAR testCase;
  118. //
  119. // Parse cmd line
  120. //
  121. if (!ParseCmdLine(Argc,Argv)) {
  122. return 1;
  123. }
  124. //
  125. // Create the test file
  126. //
  127. if (!CreateTestFile()) {
  128. return 2;
  129. }
  130. //
  131. // Call appropriate test routine.
  132. //
  133. testCase = (Test << 1) | Access;
  134. switch (testCase) {
  135. case 0:
  136. if (!ReadSequential(Iterations)) {
  137. return 3;
  138. }
  139. break;
  140. case 1:
  141. //
  142. // Read random
  143. //
  144. if (!ReadRandom(Iterations)) {
  145. return 3;
  146. }
  147. break;
  148. case 2:
  149. if (!WriteSequential(Iterations)) {
  150. return 3;
  151. }
  152. break;
  153. case 3:
  154. //
  155. // Write random
  156. //
  157. if (!WriteRandom(Iterations)) {
  158. return 3;
  159. }
  160. break;
  161. default:
  162. printf("Invalid test case\n");
  163. return 3;
  164. }
  165. return 0;
  166. }
  167. BOOLEAN
  168. CreateTestFile(
  169. VOID
  170. )
  171. {
  172. PUCHAR buffer;
  173. HANDLE port = INVALID_HANDLE_VALUE;
  174. HANDLE fileHandle;
  175. OVERLAPPED overlapped,*overlapped2;
  176. DWORD bytesTransferred,bytesTransferred2;
  177. DWORD_PTR key;
  178. ULONG numberWrites, numberQueued;
  179. BOOL status;
  180. ULONG i;
  181. DWORD currentSize;
  182. buffer = VirtualAlloc(NULL,
  183. DEFAULT_BUFFER_SIZE,
  184. MEM_COMMIT,
  185. PAGE_READWRITE);
  186. if ( !buffer ) {
  187. printf("Error allocating buffer %x\n",GetLastError());
  188. return FALSE;
  189. }
  190. if(ReuseFile) {
  191. fileHandle = CreateFile(FileName,
  192. ReadOnly ? GENERIC_READ :
  193. (GENERIC_READ | GENERIC_WRITE),
  194. 0,
  195. NULL,
  196. OPEN_EXISTING,
  197. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  198. NULL);
  199. if(fileHandle != INVALID_HANDLE_VALUE) {
  200. Log(1, "Using existing test file %s\n", FileName);
  201. goto InitializeTestFile;
  202. } else {
  203. Log(1, "Error %d opening existing test file\n", GetLastError());
  204. }
  205. } else {
  206. DeleteFile(FileName);
  207. }
  208. fileHandle = CreateFile(FileName,
  209. GENERIC_READ | GENERIC_WRITE,
  210. 0,
  211. NULL,
  212. OPEN_ALWAYS,
  213. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  214. NULL);
  215. InitializeTestFile:
  216. if ( fileHandle == INVALID_HANDLE_VALUE ) {
  217. printf("Error opening file %s %d\n",FileName,GetLastError());
  218. return FALSE;
  219. }
  220. currentSize = GetFileSize(fileHandle, NULL);
  221. if(currentSize >= FileSize) {
  222. goto EndCreateTestFile;
  223. } else if(ReadOnly) {
  224. FileSize = currentSize;
  225. goto EndCreateTestFile;
  226. }
  227. //
  228. // Uncompress the file - compressed files will always do cached I/O even
  229. // if you tell them not to. If this fails assume it's because the
  230. // underlying file system doesn't handle compression.
  231. //
  232. Log(1, "Trying to decompress %s\n", FileName);
  233. YaptSetFileCompression(fileHandle, COMPRESSION_FORMAT_NONE);
  234. port = CreateIoCompletionPort(fileHandle,
  235. NULL,
  236. (DWORD_PTR)fileHandle,
  237. 0);
  238. if ( !port ) {
  239. printf("Error creating completion port %d\n",GetLastError());
  240. return FALSE;
  241. }
  242. Log(1,"Creating test file %s",FileName);
  243. memset(&overlapped, 0, sizeof(overlapped));
  244. numberWrites = FileSize / BufferSize;
  245. if (!QueueSize || QueueSize > FileSize) {
  246. QueueSize = FileSize;
  247. }
  248. numberQueued = QueueSize / BufferSize;
  249. for (i = 0; i < numberQueued; i++) {
  250. retryWrite:
  251. status = WriteFile(fileHandle,
  252. buffer,
  253. BufferSize,
  254. &bytesTransferred,
  255. &overlapped);
  256. if ( !status && GetLastError() != ERROR_IO_PENDING ) {
  257. if (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  258. GetLastError() == ERROR_NOT_ENOUGH_QUOTA ||
  259. GetLastError() == ERROR_WORKING_SET_QUOTA ||
  260. GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
  261. goto retryWrite;
  262. }
  263. printf("Error creating test file %x\n",GetLastError());
  264. return FALSE;
  265. }
  266. Log(2,".");
  267. overlapped.Offset += BufferSize;
  268. }
  269. for (i = 0; i < numberWrites; i++ ) {
  270. status = GetQueuedCompletionStatus(port,
  271. &bytesTransferred2,
  272. &key,
  273. &overlapped2,
  274. (DWORD)-1);
  275. if ( !status ) {
  276. printf("Error on completion during test file create %x\n",GetLastError());
  277. return FALSE;
  278. }
  279. if (numberQueued < numberWrites) {
  280. numberQueued++;
  281. for (;;) {
  282. status = WriteFile(fileHandle,
  283. buffer,
  284. BufferSize,
  285. &bytesTransferred,
  286. &overlapped);
  287. if ( !status && GetLastError() != ERROR_IO_PENDING ) {
  288. if (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  289. GetLastError() == ERROR_NOT_ENOUGH_QUOTA ||
  290. GetLastError() == ERROR_WORKING_SET_QUOTA ||
  291. GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
  292. continue;
  293. }
  294. printf("Error creating test file %x\n",GetLastError());
  295. return FALSE;
  296. }
  297. break;
  298. }
  299. Log(2,".");
  300. overlapped.Offset += BufferSize;
  301. }
  302. }
  303. Log(1,".. Complete.\n\n");
  304. EndCreateTestFile:
  305. if(port != INVALID_HANDLE_VALUE) CloseHandle(port);
  306. if(fileHandle != INVALID_HANDLE_VALUE) CloseHandle(fileHandle);
  307. VirtualFree(buffer,
  308. DEFAULT_BUFFER_SIZE,
  309. MEM_DECOMMIT);
  310. return TRUE;
  311. }
  312. BOOLEAN
  313. ReadSequential(
  314. ULONG Iterations
  315. )
  316. {
  317. ULONG j,
  318. outstandingRequests,
  319. remaining = Iterations;
  320. ULONG start,end;
  321. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  322. DOUBLE iops;
  323. HANDLE file,
  324. port;
  325. OVERLAPPED overlapped,
  326. *overlapped2;
  327. DWORD bytesRead,
  328. bytesRead2,
  329. errCode,
  330. version;
  331. DWORD_PTR completionKey;
  332. BOOL status;
  333. PUCHAR buffer;
  334. ULONG totalIO = 0;
  335. printf("Starting Sequential Reads of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  336. version = GetVersion() >> 16;
  337. buffer = VirtualAlloc(NULL,
  338. BufferSize + SectorSize - 1,
  339. MEM_COMMIT | MEM_RESERVE,
  340. PAGE_READWRITE);
  341. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  342. if ( !buffer ) {
  343. Log(0,"Error allocating buffer: %x\n",GetLastError());
  344. return FALSE;
  345. }
  346. file = CreateFile(FileName,
  347. ReadOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
  348. 0,
  349. NULL,
  350. OPEN_EXISTING,
  351. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  352. NULL );
  353. if ( file == INVALID_HANDLE_VALUE ) {
  354. Log(0,"Error opening Target file: %x\n",GetLastError());
  355. VirtualFree(buffer,
  356. BufferSize + SectorSize - 1,
  357. MEM_DECOMMIT);
  358. return FALSE;
  359. }
  360. port = CreateIoCompletionPort(file,
  361. NULL,
  362. (DWORD_PTR)file,
  363. 0);
  364. if ( !port ) {
  365. Log(0,"Error creating completion port: %x\n",GetLastError());
  366. VirtualFree(buffer,
  367. BufferSize + SectorSize - 1,
  368. MEM_DECOMMIT);
  369. return FALSE;
  370. }
  371. while (remaining--) {
  372. start = GetTickCount();
  373. memset(&overlapped,0,sizeof(overlapped));
  374. outstandingRequests = 0;
  375. if (!QueueSize || QueueSize > FileSize) {
  376. QueueSize = FileSize;
  377. }
  378. for (j = 0; j < QueueSize / BufferSize; j++) {
  379. do {
  380. status = ReadFile(file,
  381. buffer,
  382. BufferSize,
  383. &bytesRead,
  384. &overlapped);
  385. errCode = GetLastError();
  386. if (!status) {
  387. if (errCode == ERROR_IO_PENDING) {
  388. break;
  389. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  390. errCode == ERROR_INVALID_USER_BUFFER ||
  391. errCode == ERROR_WORKING_SET_QUOTA ||
  392. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  393. //
  394. // Allow this to retry.
  395. //
  396. } else {
  397. Log(0,"Error in ReadFile: %x\n",errCode);
  398. VirtualFree(buffer,
  399. BufferSize + SectorSize - 1,
  400. MEM_DECOMMIT);
  401. return FALSE;
  402. }
  403. }
  404. } while (!status);
  405. outstandingRequests++;
  406. totalIO++;
  407. overlapped.Offset += BufferSize;
  408. }
  409. for (j = 0; j < FileSize / BufferSize; j++) {
  410. status = GetQueuedCompletionStatus(port,
  411. &bytesRead2,
  412. &completionKey,
  413. &overlapped2,
  414. (DWORD)-1);
  415. if (!status) {
  416. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  417. VirtualFree(buffer,
  418. BufferSize + SectorSize - 1,
  419. MEM_DECOMMIT);
  420. return FALSE;
  421. }
  422. if (outstandingRequests < FileSize / BufferSize) {
  423. do {
  424. status = ReadFile(file,
  425. buffer,
  426. BufferSize,
  427. &bytesRead,
  428. &overlapped);
  429. errCode = GetLastError();
  430. if (!status) {
  431. if (errCode == ERROR_IO_PENDING) {
  432. break;
  433. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  434. errCode == ERROR_INVALID_USER_BUFFER ||
  435. errCode == ERROR_WORKING_SET_QUOTA ||
  436. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  437. //
  438. // Allow this to retry.
  439. //
  440. } else {
  441. Log(0,"Error in ReadFile: %x\n",errCode);
  442. VirtualFree(buffer,
  443. BufferSize + SectorSize - 1,
  444. MEM_DECOMMIT);
  445. return FALSE;
  446. }
  447. }
  448. } while (!status);
  449. totalIO++;
  450. outstandingRequests++;
  451. overlapped.Offset += BufferSize;
  452. }
  453. }
  454. end = GetTickCount();
  455. testTime = end - start;
  456. testTime /= 1000.0;
  457. seconds += testTime;
  458. Log(1,"Iteration %2d -> %4.3f MB/S\n",
  459. Iterations - remaining,
  460. (FileSize / testTime)/(1024*1024));
  461. }
  462. CloseHandle(port);
  463. CloseHandle(file);
  464. thruPut = FileSize * Iterations / seconds;
  465. iops = totalIO / seconds;
  466. printf("\nAverage Throughput %4.3f IO/S %4.3f\n",
  467. thruPut/(1024*1024),
  468. iops);
  469. VirtualFree(buffer,
  470. BufferSize + SectorSize - 1,
  471. MEM_DECOMMIT);
  472. return TRUE;
  473. }
  474. BOOLEAN
  475. ReadRandom(
  476. ULONG Iterations
  477. )
  478. {
  479. ULONG j,
  480. outstandingRequests,
  481. remaining = Iterations;
  482. ULONG start,end;
  483. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  484. DOUBLE iops;
  485. HANDLE file,
  486. port;
  487. OVERLAPPED overlapped,
  488. *overlapped2;
  489. DWORD bytesRead,
  490. bytesRead2,
  491. errCode,
  492. version;
  493. DWORD_PTR completionKey;
  494. BOOL status;
  495. PUCHAR buffer;
  496. ULONG min = FileSize,max = 0;
  497. ULONG totalIO = 0;
  498. printf("Starting Random Reads of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  499. version = GetVersion() >> 16;
  500. srand((unsigned)time(NULL));
  501. buffer = VirtualAlloc(NULL,
  502. BufferSize + SectorSize - 1,
  503. MEM_COMMIT | MEM_RESERVE,
  504. PAGE_READWRITE);
  505. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  506. if ( !buffer ) {
  507. Log(0,"Error allocating buffer: %x\n",GetLastError());
  508. return FALSE;
  509. }
  510. file = CreateFile(FileName,
  511. ReadOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
  512. 0,
  513. NULL,
  514. OPEN_EXISTING,
  515. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  516. NULL );
  517. if ( file == INVALID_HANDLE_VALUE ) {
  518. Log(0,"Error opening Target file: %x\n",GetLastError());
  519. VirtualFree(buffer,
  520. BufferSize + SectorSize - 1,
  521. MEM_DECOMMIT);
  522. return FALSE;
  523. }
  524. port = CreateIoCompletionPort(file,
  525. NULL,
  526. (DWORD_PTR)file,
  527. 0);
  528. if ( !port ) {
  529. Log(0,"Error creating completion port: %x\n",GetLastError());
  530. VirtualFree(buffer,
  531. BufferSize + SectorSize - 1,
  532. MEM_DECOMMIT);
  533. return FALSE;
  534. }
  535. while (remaining--) {
  536. start = GetTickCount();
  537. memset(&overlapped,0,sizeof(overlapped));
  538. outstandingRequests = 0;
  539. if (!QueueSize || QueueSize > FileSize) {
  540. QueueSize = FileSize;
  541. }
  542. for (j = 0; j < QueueSize / BufferSize; j++) {
  543. do {
  544. status = ReadFile(file,
  545. buffer,
  546. BufferSize,
  547. &bytesRead,
  548. &overlapped);
  549. errCode = GetLastError();
  550. if (!status) {
  551. if (errCode == ERROR_IO_PENDING) {
  552. break;
  553. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  554. errCode == ERROR_INVALID_USER_BUFFER ||
  555. errCode == ERROR_WORKING_SET_QUOTA ||
  556. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  557. //
  558. // Allow this to retry.
  559. //
  560. } else {
  561. Log(0,"Error in ReadFile: %x\n",errCode);
  562. VirtualFree(buffer,
  563. BufferSize + SectorSize - 1,
  564. MEM_DECOMMIT);
  565. return FALSE;
  566. }
  567. }
  568. } while (!status);
  569. outstandingRequests++;
  570. totalIO++;
  571. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  572. if (overlapped.Offset > max) {
  573. max = overlapped.Offset;
  574. }
  575. if (overlapped.Offset < min) {
  576. min = overlapped.Offset;
  577. }
  578. }
  579. for (j = 0; j < FileSize / BufferSize; j++) {
  580. status = GetQueuedCompletionStatus(port,
  581. &bytesRead2,
  582. &completionKey,
  583. &overlapped2,
  584. (DWORD)-1);
  585. if (!status) {
  586. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  587. VirtualFree(buffer,
  588. BufferSize + SectorSize - 1,
  589. MEM_DECOMMIT);
  590. return FALSE;
  591. }
  592. if (outstandingRequests < FileSize / BufferSize) {
  593. do {
  594. status = ReadFile(file,
  595. buffer,
  596. BufferSize,
  597. &bytesRead,
  598. &overlapped);
  599. errCode = GetLastError();
  600. if (!status) {
  601. if (errCode == ERROR_IO_PENDING) {
  602. break;
  603. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  604. errCode == ERROR_INVALID_USER_BUFFER ||
  605. errCode == ERROR_WORKING_SET_QUOTA ||
  606. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  607. //
  608. // Allow this to retry.
  609. //
  610. } else {
  611. Log(0,"Error in ReadFile: %x\n",errCode);
  612. VirtualFree(buffer,
  613. BufferSize + SectorSize - 1,
  614. MEM_DECOMMIT);
  615. return FALSE;
  616. }
  617. }
  618. } while (!status);
  619. outstandingRequests++;
  620. totalIO++;
  621. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  622. if (overlapped.Offset > max) {
  623. max = overlapped.Offset;
  624. }
  625. if (overlapped.Offset < min) {
  626. min = overlapped.Offset;
  627. }
  628. }
  629. }
  630. end = GetTickCount();
  631. testTime = end - start;
  632. testTime /= 1000.0;
  633. seconds += testTime;
  634. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  635. }
  636. CloseHandle(port);
  637. CloseHandle(file);
  638. iops = totalIO / seconds;
  639. thruPut = FileSize * Iterations / seconds;
  640. printf("\nAverage Throughput %4.3f MB/S. IO/S %4.3f\n",
  641. thruPut/(1024*1024),
  642. iops);
  643. Log(2,"Min = %Lu, Max = %Lu, FileSize = %Lu\n",min,max,FileSize);
  644. VirtualFree(buffer,
  645. BufferSize + SectorSize - 1,
  646. MEM_DECOMMIT);
  647. return TRUE;
  648. }
  649. BOOLEAN
  650. WriteSequential(
  651. ULONG Iterations
  652. )
  653. {
  654. ULONG j,
  655. outstandingRequests,
  656. remaining = Iterations;
  657. ULONG start,end;
  658. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  659. DOUBLE iops;
  660. HANDLE file,
  661. port;
  662. OVERLAPPED overlapped,
  663. *overlapped2;
  664. DWORD bytesWritten,
  665. bytesWritten2,
  666. errCode,
  667. version;
  668. DWORD_PTR completionKey;
  669. BOOL status;
  670. PUCHAR buffer;
  671. ULONG totalIO = 0;
  672. if(ReadOnly) {
  673. printf("Can't run write tests on a read only file\n");
  674. return FALSE;
  675. }
  676. printf("Starting Sequential Writes of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  677. version = GetVersion() >> 16;
  678. buffer = VirtualAlloc(NULL,
  679. BufferSize + SectorSize - 1,
  680. MEM_COMMIT | MEM_RESERVE,
  681. PAGE_READWRITE);
  682. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  683. if ( !buffer ) {
  684. Log(0,"Error allocating buffer: %x\n",GetLastError());
  685. return FALSE;
  686. }
  687. file = CreateFile(FileName,
  688. GENERIC_READ | GENERIC_WRITE,
  689. 0,
  690. NULL,
  691. OPEN_EXISTING,
  692. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  693. NULL );
  694. if ( file == INVALID_HANDLE_VALUE ) {
  695. Log(0,"Error opening Target file: %x\n",GetLastError());
  696. VirtualFree(buffer,
  697. BufferSize + SectorSize - 1,
  698. MEM_DECOMMIT);
  699. return FALSE;
  700. }
  701. port = CreateIoCompletionPort(file,
  702. NULL,
  703. (DWORD_PTR)file,
  704. 0);
  705. if ( !port ) {
  706. Log(0,"Error creating completion port: %x\n",GetLastError());
  707. VirtualFree(buffer,
  708. BufferSize + SectorSize - 1,
  709. MEM_DECOMMIT);
  710. return FALSE;
  711. }
  712. while (remaining--) {
  713. start = GetTickCount();
  714. memset(&overlapped,0,sizeof(overlapped));
  715. outstandingRequests = 0;
  716. if (!QueueSize || QueueSize > FileSize) {
  717. QueueSize = FileSize;
  718. }
  719. for (j = 0; j < QueueSize / BufferSize; j++) {
  720. do {
  721. status = WriteFile(file,
  722. buffer,
  723. BufferSize,
  724. &bytesWritten,
  725. &overlapped);
  726. errCode = GetLastError();
  727. if (!status) {
  728. if (errCode == ERROR_IO_PENDING) {
  729. break;
  730. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  731. errCode == ERROR_INVALID_USER_BUFFER ||
  732. errCode == ERROR_WORKING_SET_QUOTA ||
  733. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  734. //
  735. // Allow this to retry.
  736. //
  737. } else {
  738. Log(0,"Error in WriteFile: %x\n",errCode);
  739. VirtualFree(buffer,
  740. BufferSize + SectorSize - 1,
  741. MEM_DECOMMIT);
  742. return FALSE;
  743. }
  744. }
  745. } while (!status);
  746. outstandingRequests++;
  747. totalIO++;
  748. overlapped.Offset += BufferSize;
  749. }
  750. for (j = 0; j < FileSize / BufferSize; j++) {
  751. status = GetQueuedCompletionStatus(port,
  752. &bytesWritten2,
  753. &completionKey,
  754. &overlapped2,
  755. (DWORD)-1);
  756. if (!status) {
  757. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  758. VirtualFree(buffer,
  759. BufferSize + SectorSize - 1,
  760. MEM_DECOMMIT);
  761. return FALSE;
  762. }
  763. if (outstandingRequests < FileSize / BufferSize) {
  764. do {
  765. status = WriteFile(file,
  766. buffer,
  767. BufferSize,
  768. &bytesWritten,
  769. &overlapped);
  770. errCode = GetLastError();
  771. if (!status) {
  772. if (errCode == ERROR_IO_PENDING) {
  773. break;
  774. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  775. errCode == ERROR_INVALID_USER_BUFFER ||
  776. errCode == ERROR_WORKING_SET_QUOTA ||
  777. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  778. //
  779. // Allow this to retry.
  780. //
  781. } else {
  782. Log(0,"Error in WriteFile: %x\n",errCode);
  783. VirtualFree(buffer,
  784. BufferSize + SectorSize - 1,
  785. MEM_DECOMMIT);
  786. return FALSE;
  787. }
  788. }
  789. } while (!status);
  790. outstandingRequests++;
  791. totalIO++;
  792. overlapped.Offset += BufferSize;
  793. }
  794. }
  795. end = GetTickCount();
  796. testTime = end - start;
  797. testTime /= 1000.0;
  798. seconds += testTime;
  799. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  800. }
  801. CloseHandle(port);
  802. CloseHandle(file);
  803. thruPut = FileSize * Iterations / seconds;
  804. iops = totalIO / seconds;
  805. printf("\nAverage Throughput %4.3f IO/S %4.3f\n",
  806. thruPut/(1024*1024),
  807. iops);
  808. VirtualFree(buffer,
  809. BufferSize + SectorSize - 1,
  810. MEM_DECOMMIT);
  811. return TRUE;
  812. }
  813. BOOLEAN
  814. WriteRandom(
  815. ULONG Iterations
  816. )
  817. {
  818. ULONG j,
  819. outstandingRequests,
  820. remaining = Iterations;
  821. ULONG start,end;
  822. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  823. DOUBLE iops;
  824. HANDLE file,
  825. port;
  826. OVERLAPPED overlapped,
  827. *overlapped2;
  828. DWORD bytesWritten,
  829. bytesWritten2,
  830. errCode,
  831. version;
  832. DWORD_PTR completionKey;
  833. BOOL status;
  834. PUCHAR buffer;
  835. ULONG min = FileSize,max = 0;
  836. ULONG totalIO = 0;
  837. if(ReadOnly) {
  838. printf("Can't run write tests on a read only file\n");
  839. return FALSE;
  840. }
  841. printf("Starting Random Writes of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  842. version = GetVersion() >> 16;
  843. buffer = VirtualAlloc(NULL,
  844. BufferSize + SectorSize - 1,
  845. MEM_COMMIT | MEM_RESERVE,
  846. PAGE_READWRITE);
  847. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  848. if ( !buffer ) {
  849. Log(0,"Error allocating buffer: %x\n",GetLastError());
  850. return FALSE;
  851. }
  852. file = CreateFile(FileName,
  853. GENERIC_READ | GENERIC_WRITE,
  854. 0,
  855. NULL,
  856. OPEN_EXISTING,
  857. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  858. NULL );
  859. if ( file == INVALID_HANDLE_VALUE ) {
  860. Log(0,"Error opening Target file: %x\n",GetLastError());
  861. VirtualFree(buffer,
  862. BufferSize + SectorSize - 1,
  863. MEM_DECOMMIT);
  864. return FALSE;
  865. }
  866. port = CreateIoCompletionPort(file,
  867. NULL,
  868. (DWORD_PTR)file,
  869. 0);
  870. if ( !port ) {
  871. Log(0,"Error creating completion port: %x\n",GetLastError());
  872. VirtualFree(buffer,
  873. BufferSize + SectorSize - 1,
  874. MEM_DECOMMIT);
  875. return FALSE;
  876. }
  877. while (remaining--) {
  878. start = GetTickCount();
  879. memset(&overlapped,0,sizeof(overlapped));
  880. outstandingRequests = 0;
  881. if (!QueueSize || QueueSize > FileSize) {
  882. QueueSize = FileSize;
  883. }
  884. for (j = 0; j < QueueSize / BufferSize; j++) {
  885. do {
  886. status = WriteFile(file,
  887. buffer,
  888. BufferSize,
  889. &bytesWritten,
  890. &overlapped);
  891. errCode = GetLastError();
  892. if (!status) {
  893. if (errCode == ERROR_IO_PENDING) {
  894. break;
  895. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  896. errCode == ERROR_INVALID_USER_BUFFER ||
  897. errCode == ERROR_WORKING_SET_QUOTA ||
  898. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  899. //
  900. // Allow this to retry.
  901. //
  902. } else {
  903. Log(0,"Error in WriteFile: %x\n",errCode);
  904. VirtualFree(buffer,
  905. BufferSize + SectorSize - 1,
  906. MEM_DECOMMIT);
  907. return FALSE;
  908. }
  909. }
  910. } while (!status);
  911. outstandingRequests++;
  912. totalIO++;
  913. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  914. if (overlapped.Offset > max) {
  915. max = overlapped.Offset;
  916. }
  917. if (overlapped.Offset < min) {
  918. min = overlapped.Offset;
  919. }
  920. }
  921. for (j = 0; j < FileSize / BufferSize; j++) {
  922. status = GetQueuedCompletionStatus(port,
  923. &bytesWritten2,
  924. &completionKey,
  925. &overlapped2,
  926. (DWORD)-1);
  927. if (!status) {
  928. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  929. VirtualFree(buffer,
  930. BufferSize + SectorSize - 1,
  931. MEM_DECOMMIT);
  932. return FALSE;
  933. }
  934. if (outstandingRequests < FileSize / BufferSize) {
  935. do {
  936. status = WriteFile(file,
  937. buffer,
  938. BufferSize,
  939. &bytesWritten,
  940. &overlapped);
  941. errCode = GetLastError();
  942. if (!status) {
  943. if (errCode == ERROR_IO_PENDING) {
  944. break;
  945. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  946. errCode == ERROR_INVALID_USER_BUFFER ||
  947. errCode == ERROR_WORKING_SET_QUOTA ||
  948. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  949. //
  950. // Allow this to retry.
  951. //
  952. } else {
  953. Log(0,"Error in WriteFile: %x\n",errCode);
  954. VirtualFree(buffer,
  955. BufferSize + SectorSize - 1,
  956. MEM_DECOMMIT);
  957. return FALSE;
  958. }
  959. }
  960. } while (!status);
  961. outstandingRequests++;
  962. totalIO++;
  963. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  964. if (overlapped.Offset > max) {
  965. max = overlapped.Offset;
  966. }
  967. if (overlapped.Offset < min) {
  968. min = overlapped.Offset;
  969. }
  970. }
  971. }
  972. end = GetTickCount();
  973. testTime = end - start;
  974. testTime /= 1000.0;
  975. seconds += testTime;
  976. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  977. }
  978. CloseHandle(port);
  979. CloseHandle(file);
  980. thruPut = FileSize * Iterations / seconds;
  981. iops = totalIO / seconds;
  982. printf("\nAverage Throughput %4.3f IO/S %4.3f\n",
  983. thruPut/(1024*1024),
  984. iops);
  985. Log(2,"Min = %Lu, Max = %Lu, FileSize = %Lu\n",min,max,FileSize);
  986. VirtualFree(buffer,
  987. BufferSize + SectorSize - 1,
  988. MEM_DECOMMIT);
  989. return TRUE;
  990. }
  991. ULONG
  992. GetRandomOffset(
  993. ULONG min,
  994. ULONG max
  995. )
  996. {
  997. INT base = rand();
  998. ULONG retval = ((max - min) / RAND_MAX) * base;
  999. retval += SectorSize - 1;
  1000. retval &= ~(SectorSize - 1);
  1001. if (retval < min) {
  1002. return min;
  1003. } else if (retval > max ){
  1004. return max & ~(SectorSize - 1);
  1005. } else{
  1006. return retval;
  1007. }
  1008. }
  1009. BOOLEAN
  1010. ParseCmdLine(
  1011. INT Argc,
  1012. CHAR *Argv[]
  1013. )
  1014. {
  1015. INT i;
  1016. CHAR *switches = " ,-";
  1017. CHAR swtch,*value,*str;
  1018. BOOLEAN gotSwitch = FALSE;
  1019. if (Argc <= 1) {
  1020. //
  1021. // Using defaults
  1022. //
  1023. return TRUE;
  1024. }
  1025. for (i = 1; i < Argc; i++) {
  1026. str = Argv[i];
  1027. value = strtok(str, switches);
  1028. if (gotSwitch) {
  1029. if (!ValidateOption(swtch,value)) {
  1030. Usage();
  1031. return FALSE;
  1032. } else {
  1033. gotSwitch = FALSE;
  1034. }
  1035. } else {
  1036. gotSwitch = TRUE;
  1037. swtch = value[0];
  1038. if (value[1] || swtch == '?') {
  1039. Usage();
  1040. return FALSE;
  1041. }
  1042. }
  1043. }
  1044. if (gotSwitch) {
  1045. Usage();
  1046. return FALSE;
  1047. } else {
  1048. return TRUE;
  1049. }
  1050. }
  1051. BOOLEAN
  1052. ValidateOption(
  1053. CHAR Switch,
  1054. CHAR *Value
  1055. )
  1056. {
  1057. Switch = (CHAR)toupper(Switch);
  1058. switch (Switch) {
  1059. case 'F':
  1060. VerifyFileName(Value);
  1061. strcpy(FileName,Value);
  1062. break;
  1063. case 'T':
  1064. if (_stricmp(Value,"READ")==0) {
  1065. Test = READ;
  1066. } else if (_stricmp(Value,"WRITE")==0) {
  1067. Test = WRITE;
  1068. } else {
  1069. return FALSE;
  1070. }
  1071. break;
  1072. case 'A':
  1073. if (_strnicmp(Value,"SEQ",3)==0) {
  1074. Access = SEQ;
  1075. } else if (_strnicmp(Value,"RAND",4)==0) {
  1076. Access = RAND;
  1077. } else {
  1078. return FALSE;
  1079. }
  1080. break;
  1081. case 'B':
  1082. BufferSize = atol(Value);
  1083. //
  1084. // TODO:Adjust buffersize to multiple of a sector and #of K.
  1085. //
  1086. BufferSize *= 1024;
  1087. break;
  1088. case 'S':
  1089. FileSize = atol(Value);
  1090. //
  1091. // TODO: Adjust filesize to multiple of buffersize and #of Meg.
  1092. //
  1093. FileSize *= 1024*1024;
  1094. break;
  1095. case 'Q':
  1096. QueueSize = atol(Value);
  1097. QueueSize *= 1024*1024;
  1098. break;
  1099. case 'V':
  1100. Verbose = atol(Value);
  1101. break;
  1102. case 'I':
  1103. Iterations = atol(Value);
  1104. break;
  1105. case 'R':
  1106. if(tolower(Value[0]) == 'y') {
  1107. ReuseFile = TRUE;
  1108. } else {
  1109. ReuseFile = FALSE;
  1110. }
  1111. break;
  1112. case 'O':
  1113. if(tolower(Value[0]) == 'y') {
  1114. ReadOnly = TRUE;
  1115. } else {
  1116. ReadOnly = FALSE;
  1117. }
  1118. break;
  1119. default:
  1120. return FALSE;
  1121. }
  1122. return TRUE;
  1123. }
  1124. VOID
  1125. Usage(
  1126. VOID
  1127. )
  1128. {
  1129. fprintf(stderr,"usage: YAPT (Yet another performance tool)\n"
  1130. " -f [filename]\n"
  1131. " -t [Test:Read,Write]\n"
  1132. " -a [Access Mode:Seq or Random]\n"
  1133. " -b [buffer size in KB]\n"
  1134. " -s [filesize]\n"
  1135. " -i [Iterations]\n"
  1136. " -v [Verbosity: 0-2]\n"
  1137. " -r [Reuse test file: yes, no]\n"
  1138. " -o [Read Only: yes, no]\n"
  1139. " -q [queuesize in MB]\n"
  1140. );
  1141. }
  1142. VOID
  1143. __cdecl
  1144. Log(
  1145. ULONG LogLevel,
  1146. PCHAR String,
  1147. ...
  1148. )
  1149. {
  1150. CHAR Buffer[256];
  1151. va_list argp;
  1152. va_start(argp, String);
  1153. if (LogLevel <= Verbose) {
  1154. vsprintf(Buffer, String, argp);
  1155. printf("%s",Buffer);
  1156. }
  1157. va_end(argp);
  1158. }
  1159. DWORD
  1160. YaptSetFileCompression(
  1161. IN HANDLE FileHandle,
  1162. IN USHORT CompressionFormat
  1163. )
  1164. {
  1165. DWORD bytesReturned;
  1166. assert(FileHandle != INVALID_HANDLE_VALUE);
  1167. if(!DeviceIoControl(
  1168. FileHandle,
  1169. FSCTL_SET_COMPRESSION,
  1170. &CompressionFormat,
  1171. sizeof(CompressionFormat),
  1172. NULL,
  1173. 0,
  1174. &bytesReturned,
  1175. NULL)) {
  1176. }
  1177. return GetLastError();
  1178. }
  1179. VOID
  1180. VerifyFileName(
  1181. IN CHAR *FileName
  1182. )
  1183. {
  1184. CHAR input[32];
  1185. if(Yes) return;
  1186. if(((FileName[0] == '\\') || (FileName[0] == '/')) &&
  1187. ((FileName[1] == '\\') || (FileName[1] == '/')) &&
  1188. ((FileName[2] == '.') || (FileName[2] == '?')) &&
  1189. ((FileName[3] == '\\') || (FileName[3] == '/'))) {
  1190. printf("\n\t%s looks like a raw device\n"
  1191. "\tdo you want to continue? ", FileName);
  1192. fflush(stdout);
  1193. if(fgets(input, 32, stdin) == NULL) {
  1194. printf("\nQuitting\n");
  1195. exit(-1);
  1196. }
  1197. if(tolower(input[0]) != 'y') {
  1198. printf("\nNegative response - quitting\n");
  1199. exit(-1);
  1200. }
  1201. }
  1202. return;
  1203. }