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.

1299 lines
31 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. UCHAR FileName[MAX_PATH] = "test.dat";
  103. UCHAR Test = READ;
  104. UCHAR Access = SEQ;
  105. ULONG Verbose = 0;
  106. ULONG Iterations = 10;
  107. UCHAR ReuseFile = TRUE;
  108. UCHAR Yes = FALSE;
  109. BOOLEAN ReadOnly = FALSE;
  110. INT
  111. _cdecl main (
  112. INT Argc,
  113. CHAR *Argv[]
  114. )
  115. {
  116. UCHAR testCase;
  117. //
  118. // Parse cmd line
  119. //
  120. if (!ParseCmdLine(Argc,Argv)) {
  121. return 1;
  122. }
  123. //
  124. // Create the test file
  125. //
  126. if (!CreateTestFile()) {
  127. return 2;
  128. }
  129. //
  130. // Call appropriate test routine.
  131. //
  132. testCase = (Test << 1) | Access;
  133. switch (testCase) {
  134. case 0:
  135. if (!ReadSequential(Iterations)) {
  136. return 3;
  137. }
  138. break;
  139. case 1:
  140. //
  141. // Read random
  142. //
  143. if (!ReadRandom(Iterations)) {
  144. return 3;
  145. }
  146. break;
  147. case 2:
  148. if (!WriteSequential(Iterations)) {
  149. return 3;
  150. }
  151. break;
  152. case 3:
  153. //
  154. // Write random
  155. //
  156. if (!WriteRandom(Iterations)) {
  157. return 3;
  158. }
  159. break;
  160. default:
  161. printf("Invalid test case\n");
  162. return 3;
  163. }
  164. return 0;
  165. }
  166. BOOLEAN
  167. CreateTestFile(
  168. VOID
  169. )
  170. {
  171. PUCHAR buffer;
  172. HANDLE port = INVALID_HANDLE_VALUE;
  173. HANDLE fileHandle;
  174. OVERLAPPED overlapped,*overlapped2;
  175. DWORD bytesTransferred,bytesTransferred2;
  176. DWORD_PTR key;
  177. ULONG numberWrites;
  178. BOOL status;
  179. ULONG i;
  180. DWORD currentSize;
  181. buffer = VirtualAlloc(NULL,
  182. DEFAULT_BUFFER_SIZE,
  183. MEM_COMMIT,
  184. PAGE_READWRITE);
  185. if ( !buffer ) {
  186. printf("Error allocating buffer %x\n",GetLastError());
  187. return FALSE;
  188. }
  189. if(ReuseFile) {
  190. fileHandle = CreateFile(FileName,
  191. ReadOnly ? GENERIC_READ :
  192. (GENERIC_READ | GENERIC_WRITE),
  193. 0,
  194. NULL,
  195. OPEN_EXISTING,
  196. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  197. NULL);
  198. if(fileHandle != INVALID_HANDLE_VALUE) {
  199. Log(1, "Using existing test file %s\n", FileName);
  200. goto InitializeTestFile;
  201. } else {
  202. Log(1, "Error %d opening existing test file\n", GetLastError());
  203. }
  204. } else {
  205. DeleteFile(FileName);
  206. }
  207. fileHandle = CreateFile(FileName,
  208. GENERIC_READ | GENERIC_WRITE,
  209. 0,
  210. NULL,
  211. OPEN_ALWAYS,
  212. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  213. NULL);
  214. InitializeTestFile:
  215. if ( fileHandle == INVALID_HANDLE_VALUE ) {
  216. printf("Error opening file %s %d\n",FileName,GetLastError());
  217. return FALSE;
  218. }
  219. currentSize = GetFileSize(fileHandle, NULL);
  220. if(currentSize >= FileSize) {
  221. goto EndCreateTestFile;
  222. } else if(ReadOnly) {
  223. FileSize = currentSize;
  224. goto EndCreateTestFile;
  225. }
  226. //
  227. // Uncompress the file - compressed files will always do cached I/O even
  228. // if you tell them not to. If this fails assume it's because the
  229. // underlying file system doesn't handle compression.
  230. //
  231. Log(1, "Trying to decompress %s\n", FileName);
  232. YaptSetFileCompression(fileHandle, COMPRESSION_FORMAT_NONE);
  233. port = CreateIoCompletionPort(fileHandle,
  234. NULL,
  235. (DWORD_PTR)fileHandle,
  236. 0);
  237. if ( !port ) {
  238. printf("Error creating completion port %d\n",GetLastError());
  239. return FALSE;
  240. }
  241. Log(1,"Creating test file %s",FileName);
  242. memset(&overlapped, 0, sizeof(overlapped));
  243. numberWrites = FileSize / BufferSize;
  244. for (i = 0; i < numberWrites; i++) {
  245. retryWrite:
  246. status = WriteFile(fileHandle,
  247. buffer,
  248. BufferSize,
  249. &bytesTransferred,
  250. &overlapped);
  251. if ( !status && GetLastError() != ERROR_IO_PENDING ) {
  252. if (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  253. GetLastError() == ERROR_NOT_ENOUGH_QUOTA ||
  254. GetLastError() == ERROR_WORKING_SET_QUOTA ||
  255. GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
  256. goto retryWrite;
  257. }
  258. printf("Error creating test file %x\n",GetLastError());
  259. return FALSE;
  260. }
  261. Log(2,".");
  262. overlapped.Offset += BufferSize;
  263. }
  264. for (i = 0; i < numberWrites; i++ ) {
  265. status = GetQueuedCompletionStatus(port,
  266. &bytesTransferred2,
  267. &key,
  268. &overlapped2,
  269. (DWORD)-1);
  270. if ( !status ) {
  271. printf("Error on completion during test file create %x\n",GetLastError());
  272. return FALSE;
  273. }
  274. }
  275. Log(1,".. Complete.\n\n");
  276. EndCreateTestFile:
  277. if(port != INVALID_HANDLE_VALUE) CloseHandle(port);
  278. if(fileHandle != INVALID_HANDLE_VALUE) CloseHandle(fileHandle);
  279. VirtualFree(buffer,
  280. DEFAULT_BUFFER_SIZE,
  281. MEM_DECOMMIT);
  282. return TRUE;
  283. }
  284. BOOLEAN
  285. ReadSequential(
  286. ULONG Iterations
  287. )
  288. {
  289. ULONG j,
  290. outstandingRequests,
  291. remaining = Iterations;
  292. ULONG start,end;
  293. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  294. HANDLE file,
  295. port;
  296. OVERLAPPED overlapped,
  297. *overlapped2;
  298. DWORD bytesRead,
  299. bytesRead2,
  300. errCode,
  301. version;
  302. DWORD_PTR completionKey;
  303. BOOL status;
  304. PUCHAR buffer;
  305. printf("Starting Sequential Reads of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  306. version = GetVersion() >> 16;
  307. buffer = VirtualAlloc(NULL,
  308. BufferSize + SectorSize - 1,
  309. MEM_COMMIT | MEM_RESERVE,
  310. PAGE_READWRITE);
  311. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  312. if ( !buffer ) {
  313. Log(0,"Error allocating buffer: %x\n",GetLastError());
  314. return FALSE;
  315. }
  316. file = CreateFile(FileName,
  317. ReadOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
  318. 0,
  319. NULL,
  320. OPEN_EXISTING,
  321. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  322. NULL );
  323. if ( file == INVALID_HANDLE_VALUE ) {
  324. Log(0,"Error opening Target file: %x\n",GetLastError());
  325. VirtualFree(buffer,
  326. BufferSize + SectorSize - 1,
  327. MEM_DECOMMIT);
  328. return FALSE;
  329. }
  330. port = CreateIoCompletionPort(file,
  331. NULL,
  332. (DWORD_PTR)file,
  333. 0);
  334. if ( !port ) {
  335. Log(0,"Error creating completion port: %x\n",GetLastError());
  336. VirtualFree(buffer,
  337. BufferSize + SectorSize - 1,
  338. MEM_DECOMMIT);
  339. return FALSE;
  340. }
  341. while (remaining--) {
  342. start = GetTickCount();
  343. memset(&overlapped,0,sizeof(overlapped));
  344. outstandingRequests = 0;
  345. for (j = 0; j < FileSize / BufferSize; j++) {
  346. do {
  347. status = ReadFile(file,
  348. buffer,
  349. BufferSize,
  350. &bytesRead,
  351. &overlapped);
  352. errCode = GetLastError();
  353. if (!status) {
  354. if (errCode == ERROR_IO_PENDING) {
  355. break;
  356. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  357. errCode == ERROR_INVALID_USER_BUFFER ||
  358. errCode == ERROR_WORKING_SET_QUOTA ||
  359. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  360. //
  361. // Allow this to retry.
  362. //
  363. } else {
  364. Log(0,"Error in ReadFile: %x\n",errCode);
  365. VirtualFree(buffer,
  366. BufferSize + SectorSize - 1,
  367. MEM_DECOMMIT);
  368. return FALSE;
  369. }
  370. }
  371. } while (!status);
  372. outstandingRequests++;
  373. overlapped.Offset += BufferSize;
  374. }
  375. for (j = 0; j < outstandingRequests; j++) {
  376. status = GetQueuedCompletionStatus(port,
  377. &bytesRead2,
  378. &completionKey,
  379. &overlapped2,
  380. (DWORD)-1);
  381. if (!status) {
  382. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  383. VirtualFree(buffer,
  384. BufferSize + SectorSize - 1,
  385. MEM_DECOMMIT);
  386. return FALSE;
  387. }
  388. }
  389. end = GetTickCount();
  390. testTime = end - start;
  391. testTime /= 1000.0;
  392. seconds += testTime;
  393. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  394. }
  395. CloseHandle(port);
  396. CloseHandle(file);
  397. thruPut = FileSize * Iterations / seconds;
  398. printf("\nAverage Throughput %4.3f MB/S\n",thruPut/(1024*1024));
  399. VirtualFree(buffer,
  400. BufferSize + SectorSize - 1,
  401. MEM_DECOMMIT);
  402. return TRUE;
  403. }
  404. BOOLEAN
  405. ReadRandom(
  406. ULONG Iterations
  407. )
  408. {
  409. ULONG j,
  410. outstandingRequests,
  411. remaining = Iterations;
  412. ULONG start,end;
  413. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  414. HANDLE file,
  415. port;
  416. OVERLAPPED overlapped,
  417. *overlapped2;
  418. DWORD bytesRead,
  419. bytesRead2,
  420. errCode,
  421. version;
  422. DWORD_PTR completionKey;
  423. BOOL status;
  424. PUCHAR buffer;
  425. ULONG min = FileSize,max = 0;
  426. printf("Starting Random Reads of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  427. version = GetVersion() >> 16;
  428. srand((unsigned)time(NULL));
  429. buffer = VirtualAlloc(NULL,
  430. BufferSize + SectorSize - 1,
  431. MEM_COMMIT | MEM_RESERVE,
  432. PAGE_READWRITE);
  433. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  434. if ( !buffer ) {
  435. Log(0,"Error allocating buffer: %x\n",GetLastError());
  436. return FALSE;
  437. }
  438. file = CreateFile(FileName,
  439. ReadOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
  440. 0,
  441. NULL,
  442. OPEN_EXISTING,
  443. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  444. NULL );
  445. if ( file == INVALID_HANDLE_VALUE ) {
  446. Log(0,"Error opening Target file: %x\n",GetLastError());
  447. VirtualFree(buffer,
  448. BufferSize + SectorSize - 1,
  449. MEM_DECOMMIT);
  450. return FALSE;
  451. }
  452. port = CreateIoCompletionPort(file,
  453. NULL,
  454. (DWORD_PTR)file,
  455. 0);
  456. if ( !port ) {
  457. Log(0,"Error creating completion port: %x\n",GetLastError());
  458. VirtualFree(buffer,
  459. BufferSize + SectorSize - 1,
  460. MEM_DECOMMIT);
  461. return FALSE;
  462. }
  463. while (remaining--) {
  464. start = GetTickCount();
  465. memset(&overlapped,0,sizeof(overlapped));
  466. outstandingRequests = 0;
  467. for (j = 0; j < FileSize / BufferSize; j++) {
  468. do {
  469. status = ReadFile(file,
  470. buffer,
  471. BufferSize,
  472. &bytesRead,
  473. &overlapped);
  474. errCode = GetLastError();
  475. if (!status) {
  476. if (errCode == ERROR_IO_PENDING) {
  477. break;
  478. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  479. errCode == ERROR_INVALID_USER_BUFFER ||
  480. errCode == ERROR_WORKING_SET_QUOTA ||
  481. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  482. //
  483. // Allow this to retry.
  484. //
  485. } else {
  486. Log(0,"Error in ReadFile: %x\n",errCode);
  487. VirtualFree(buffer,
  488. BufferSize + SectorSize - 1,
  489. MEM_DECOMMIT);
  490. return FALSE;
  491. }
  492. }
  493. } while (!status);
  494. outstandingRequests++;
  495. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  496. if (overlapped.Offset > max) {
  497. max = overlapped.Offset;
  498. }
  499. if (overlapped.Offset < min) {
  500. min = overlapped.Offset;
  501. }
  502. }
  503. for (j = 0; j < outstandingRequests; j++) {
  504. status = GetQueuedCompletionStatus(port,
  505. &bytesRead2,
  506. &completionKey,
  507. &overlapped2,
  508. (DWORD)-1);
  509. if (!status) {
  510. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  511. VirtualFree(buffer,
  512. BufferSize + SectorSize - 1,
  513. MEM_DECOMMIT);
  514. return FALSE;
  515. }
  516. }
  517. end = GetTickCount();
  518. testTime = end - start;
  519. testTime /= 1000.0;
  520. seconds += testTime;
  521. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  522. }
  523. CloseHandle(port);
  524. CloseHandle(file);
  525. thruPut = FileSize * Iterations / seconds;
  526. printf("\nAverage Throughput %4.3f MB/S\n",thruPut/(1024*1024));
  527. Log(2,"Min = %Lu, Max = %Lu, FileSize = %Lu\n",min,max,FileSize);
  528. VirtualFree(buffer,
  529. BufferSize + SectorSize - 1,
  530. MEM_DECOMMIT);
  531. return TRUE;
  532. }
  533. BOOLEAN
  534. WriteSequential(
  535. ULONG Iterations
  536. )
  537. {
  538. ULONG j,
  539. outstandingRequests,
  540. remaining = Iterations;
  541. ULONG start,end;
  542. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  543. HANDLE file,
  544. port;
  545. OVERLAPPED overlapped,
  546. *overlapped2;
  547. DWORD bytesWritten,
  548. bytesWritten2,
  549. errCode,
  550. version;
  551. DWORD_PTR completionKey;
  552. BOOL status;
  553. PUCHAR buffer;
  554. if(ReadOnly) {
  555. printf("Can't run write tests on a read only file\n");
  556. return FALSE;
  557. }
  558. printf("Starting Sequential Writes of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  559. version = GetVersion() >> 16;
  560. buffer = VirtualAlloc(NULL,
  561. BufferSize + SectorSize - 1,
  562. MEM_COMMIT | MEM_RESERVE,
  563. PAGE_READWRITE);
  564. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  565. if ( !buffer ) {
  566. Log(0,"Error allocating buffer: %x\n",GetLastError());
  567. return FALSE;
  568. }
  569. file = CreateFile(FileName,
  570. GENERIC_READ | GENERIC_WRITE,
  571. 0,
  572. NULL,
  573. OPEN_EXISTING,
  574. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  575. NULL );
  576. if ( file == INVALID_HANDLE_VALUE ) {
  577. Log(0,"Error opening Target file: %x\n",GetLastError());
  578. VirtualFree(buffer,
  579. BufferSize + SectorSize - 1,
  580. MEM_DECOMMIT);
  581. return FALSE;
  582. }
  583. port = CreateIoCompletionPort(file,
  584. NULL,
  585. (DWORD_PTR)file,
  586. 0);
  587. if ( !port ) {
  588. Log(0,"Error creating completion port: %x\n",GetLastError());
  589. VirtualFree(buffer,
  590. BufferSize + SectorSize - 1,
  591. MEM_DECOMMIT);
  592. return FALSE;
  593. }
  594. while (remaining--) {
  595. start = GetTickCount();
  596. memset(&overlapped,0,sizeof(overlapped));
  597. outstandingRequests = 0;
  598. for (j = 0; j < FileSize / BufferSize; j++) {
  599. do {
  600. status = WriteFile(file,
  601. buffer,
  602. BufferSize,
  603. &bytesWritten,
  604. &overlapped);
  605. errCode = GetLastError();
  606. if (!status) {
  607. if (errCode == ERROR_IO_PENDING) {
  608. break;
  609. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  610. errCode == ERROR_INVALID_USER_BUFFER ||
  611. errCode == ERROR_WORKING_SET_QUOTA ||
  612. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  613. //
  614. // Allow this to retry.
  615. //
  616. } else {
  617. Log(0,"Error in WriteFile: %x\n",errCode);
  618. VirtualFree(buffer,
  619. BufferSize + SectorSize - 1,
  620. MEM_DECOMMIT);
  621. return FALSE;
  622. }
  623. }
  624. } while (!status);
  625. outstandingRequests++;
  626. overlapped.Offset += BufferSize;
  627. }
  628. for (j = 0; j < outstandingRequests; j++) {
  629. status = GetQueuedCompletionStatus(port,
  630. &bytesWritten2,
  631. &completionKey,
  632. &overlapped2,
  633. (DWORD)-1);
  634. if (!status) {
  635. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  636. VirtualFree(buffer,
  637. BufferSize + SectorSize - 1,
  638. MEM_DECOMMIT);
  639. return FALSE;
  640. }
  641. }
  642. end = GetTickCount();
  643. testTime = end - start;
  644. testTime /= 1000.0;
  645. seconds += testTime;
  646. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  647. }
  648. CloseHandle(port);
  649. CloseHandle(file);
  650. thruPut = FileSize * Iterations / seconds;
  651. printf("\nAverage Throughput %4.3f MB/S\n",thruPut/(1024*1024));
  652. VirtualFree(buffer,
  653. BufferSize + SectorSize - 1,
  654. MEM_DECOMMIT);
  655. return TRUE;
  656. }
  657. BOOLEAN
  658. WriteRandom(
  659. ULONG Iterations
  660. )
  661. {
  662. ULONG j,
  663. outstandingRequests,
  664. remaining = Iterations;
  665. ULONG start,end;
  666. DOUBLE testTime,thruPut = 0.0,seconds = 0;
  667. HANDLE file,
  668. port;
  669. OVERLAPPED overlapped,
  670. *overlapped2;
  671. DWORD bytesWritten,
  672. bytesWritten2,
  673. errCode,
  674. version;
  675. DWORD_PTR completionKey;
  676. BOOL status;
  677. PUCHAR buffer;
  678. ULONG min = FileSize,max = 0;
  679. if(ReadOnly) {
  680. printf("Can't run write tests on a read only file\n");
  681. return FALSE;
  682. }
  683. printf("Starting Random Writes of %d Meg file, using %d K I/O size\n", FileSize / 1024*1024, BufferSize / 1024);
  684. version = GetVersion() >> 16;
  685. buffer = VirtualAlloc(NULL,
  686. BufferSize + SectorSize - 1,
  687. MEM_COMMIT | MEM_RESERVE,
  688. PAGE_READWRITE);
  689. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  690. if ( !buffer ) {
  691. Log(0,"Error allocating buffer: %x\n",GetLastError());
  692. return FALSE;
  693. }
  694. file = CreateFile(FileName,
  695. GENERIC_READ | GENERIC_WRITE,
  696. 0,
  697. NULL,
  698. OPEN_EXISTING,
  699. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  700. NULL );
  701. if ( file == INVALID_HANDLE_VALUE ) {
  702. Log(0,"Error opening Target file: %x\n",GetLastError());
  703. VirtualFree(buffer,
  704. BufferSize + SectorSize - 1,
  705. MEM_DECOMMIT);
  706. return FALSE;
  707. }
  708. port = CreateIoCompletionPort(file,
  709. NULL,
  710. (DWORD_PTR)file,
  711. 0);
  712. if ( !port ) {
  713. Log(0,"Error creating completion port: %x\n",GetLastError());
  714. VirtualFree(buffer,
  715. BufferSize + SectorSize - 1,
  716. MEM_DECOMMIT);
  717. return FALSE;
  718. }
  719. while (remaining--) {
  720. start = GetTickCount();
  721. memset(&overlapped,0,sizeof(overlapped));
  722. outstandingRequests = 0;
  723. for (j = 0; j < FileSize / BufferSize; j++) {
  724. do {
  725. status = WriteFile(file,
  726. buffer,
  727. BufferSize,
  728. &bytesWritten,
  729. &overlapped);
  730. errCode = GetLastError();
  731. if (!status) {
  732. if (errCode == ERROR_IO_PENDING) {
  733. break;
  734. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  735. errCode == ERROR_INVALID_USER_BUFFER ||
  736. errCode == ERROR_WORKING_SET_QUOTA ||
  737. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  738. //
  739. // Allow this to retry.
  740. //
  741. } else {
  742. Log(0,"Error in WriteFile: %x\n",errCode);
  743. VirtualFree(buffer,
  744. BufferSize + SectorSize - 1,
  745. MEM_DECOMMIT);
  746. return FALSE;
  747. }
  748. }
  749. } while (!status);
  750. outstandingRequests++;
  751. overlapped.Offset = GetRandomOffset(0,FileSize - BufferSize);
  752. if (overlapped.Offset > max) {
  753. max = overlapped.Offset;
  754. }
  755. if (overlapped.Offset < min) {
  756. min = overlapped.Offset;
  757. }
  758. }
  759. for (j = 0; j < outstandingRequests; j++) {
  760. status = GetQueuedCompletionStatus(port,
  761. &bytesWritten2,
  762. &completionKey,
  763. &overlapped2,
  764. (DWORD)-1);
  765. if (!status) {
  766. Log(0,"GetQueuedCompletionStatus error: %x\n",GetLastError());
  767. VirtualFree(buffer,
  768. BufferSize + SectorSize - 1,
  769. MEM_DECOMMIT);
  770. return FALSE;
  771. }
  772. }
  773. end = GetTickCount();
  774. testTime = end - start;
  775. testTime /= 1000.0;
  776. seconds += testTime;
  777. Log(1,"Iteration %2d -> %4.3f MB/S\n",Iterations - remaining,(FileSize / testTime)/(1024*1024));
  778. }
  779. CloseHandle(port);
  780. CloseHandle(file);
  781. thruPut = FileSize * Iterations / seconds;
  782. printf("\nAverage Throughput %4.3f MB/S\n",thruPut/(1024*1024));
  783. Log(2,"Min = %Lu, Max = %Lu, FileSize = %Lu\n",min,max,FileSize);
  784. VirtualFree(buffer,
  785. BufferSize + SectorSize - 1,
  786. MEM_DECOMMIT);
  787. return TRUE;
  788. }
  789. ULONG
  790. GetRandomOffset(
  791. ULONG min,
  792. ULONG max
  793. )
  794. {
  795. INT base = rand();
  796. ULONG retval = ((max - min) / RAND_MAX) * base;
  797. retval += SectorSize - 1;
  798. retval &= ~(SectorSize - 1);
  799. if (retval < min) {
  800. return min;
  801. } else if (retval > max ){
  802. return max & ~(SectorSize - 1);
  803. } else{
  804. return retval;
  805. }
  806. }
  807. BOOLEAN
  808. ParseCmdLine(
  809. INT Argc,
  810. CHAR *Argv[]
  811. )
  812. {
  813. INT i;
  814. CHAR *switches = " ,-";
  815. CHAR swtch,*value,*str;
  816. BOOLEAN gotSwitch = FALSE;
  817. if (Argc <= 1) {
  818. //
  819. // Using defaults
  820. //
  821. return TRUE;
  822. }
  823. for (i = 1; i < Argc; i++) {
  824. str = Argv[i];
  825. value = strtok(str, switches);
  826. if (gotSwitch) {
  827. if (!ValidateOption(swtch,value)) {
  828. Usage();
  829. return FALSE;
  830. } else {
  831. gotSwitch = FALSE;
  832. }
  833. } else {
  834. gotSwitch = TRUE;
  835. swtch = value[0];
  836. if (value[1] || swtch == '?') {
  837. Usage();
  838. return FALSE;
  839. }
  840. }
  841. }
  842. if (gotSwitch) {
  843. Usage();
  844. return FALSE;
  845. } else {
  846. return TRUE;
  847. }
  848. }
  849. BOOLEAN
  850. ValidateOption(
  851. CHAR Switch,
  852. CHAR *Value
  853. )
  854. {
  855. Switch = (CHAR)toupper(Switch);
  856. switch (Switch) {
  857. case 'F':
  858. VerifyFileName(Value);
  859. strcpy(FileName,Value);
  860. break;
  861. case 'T':
  862. if (_stricmp(Value,"READ")==0) {
  863. Test = READ;
  864. } else if (_stricmp(Value,"WRITE")==0) {
  865. Test = WRITE;
  866. } else {
  867. return FALSE;
  868. }
  869. break;
  870. case 'A':
  871. if (_strnicmp(Value,"SEQ",3)==0) {
  872. Access = SEQ;
  873. } else if (_strnicmp(Value,"RAND",4)==0) {
  874. Access = RAND;
  875. } else {
  876. return FALSE;
  877. }
  878. break;
  879. case 'B':
  880. BufferSize = atol(Value);
  881. //
  882. // TODO:Adjust buffersize to multiple of a sector and #of K.
  883. //
  884. BufferSize *= 1024;
  885. break;
  886. case 'S':
  887. FileSize = atol(Value);
  888. //
  889. // TODO: Adjust filesize to multiple of buffersize and #of Meg.
  890. //
  891. FileSize *= 1024*1024;
  892. break;
  893. case 'V':
  894. Verbose = atol(Value);
  895. break;
  896. case 'I':
  897. Iterations = atol(Value);
  898. break;
  899. case 'R':
  900. if(tolower(Value[0]) == 'y') {
  901. ReuseFile = TRUE;
  902. } else {
  903. ReuseFile = FALSE;
  904. }
  905. break;
  906. case 'O':
  907. if(tolower(Value[0]) == 'y') {
  908. ReadOnly = TRUE;
  909. } else {
  910. ReadOnly = FALSE;
  911. }
  912. break;
  913. default:
  914. return FALSE;
  915. }
  916. return TRUE;
  917. }
  918. VOID
  919. Usage(
  920. VOID
  921. )
  922. {
  923. fprintf(stderr,"usage: YAPT (Yet another performance tool)\n"
  924. " -f [filename]\n"
  925. " -t [Test:Read,Write]\n"
  926. " -a [Access Mode:Seq or Random]\n"
  927. " -b [buffer size in KB]\n"
  928. " -s [filesize]\n"
  929. " -i [Iterations]\n"
  930. " -v [Verbosity: 0-2]\n"
  931. " -r [Reuse test file: yes, no]\n"
  932. " -o [Read Only: yes, no]\n"
  933. );
  934. }
  935. VOID
  936. __cdecl
  937. Log(
  938. ULONG LogLevel,
  939. PCHAR String,
  940. ...
  941. )
  942. {
  943. CHAR Buffer[256];
  944. va_list argp;
  945. va_start(argp, String);
  946. if (LogLevel <= Verbose) {
  947. vsprintf(Buffer, String, argp);
  948. printf("%s",Buffer);
  949. }
  950. va_end(argp);
  951. }
  952. DWORD
  953. YaptSetFileCompression(
  954. IN HANDLE FileHandle,
  955. IN USHORT CompressionFormat
  956. )
  957. {
  958. DWORD bytesReturned;
  959. assert(FileHandle != INVALID_HANDLE_VALUE);
  960. if(!DeviceIoControl(
  961. FileHandle,
  962. FSCTL_SET_COMPRESSION,
  963. &CompressionFormat,
  964. sizeof(CompressionFormat),
  965. NULL,
  966. 0,
  967. &bytesReturned,
  968. NULL)) {
  969. }
  970. return GetLastError();
  971. }
  972. VOID
  973. VerifyFileName(
  974. IN CHAR *FileName
  975. )
  976. {
  977. CHAR input[32];
  978. if(Yes) return;
  979. if(((FileName[0] == '\\') || (FileName[0] == '/')) &&
  980. ((FileName[1] == '\\') || (FileName[1] == '/')) &&
  981. ((FileName[2] == '.') || (FileName[2] == '?')) &&
  982. ((FileName[3] == '\\') || (FileName[3] == '/'))) {
  983. printf("\n\t%s looks like a raw device\n"
  984. "\tdo you want to continue? ", FileName);
  985. fflush(stdout);
  986. if(fgets(input, 32, stdin) == NULL) {
  987. printf("\nQuitting\n");
  988. exit(-1);
  989. }
  990. if(tolower(input[0]) != 'y') {
  991. printf("\nNegative response - quitting\n");
  992. exit(-1);
  993. }
  994. }
  995. return;
  996. }