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.

1653 lines
43 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. diskmon.c
  5. Abstract:
  6. This module contians the code for the disk monitor utility.
  7. Author:
  8. Chuck Park (chuckp) 15-Feb-1994
  9. Mike Glass (mglass)
  10. Revision History:
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ntdddisk.h>
  16. #include <windows.h>
  17. #include <windowsx.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include "dskbench.h"
  23. CHAR TestDrv[8] = "\\\\.\\";
  24. CHAR TestFile[MAX_PATH];
  25. CHAR TimerText[] = "00:00:00:00";
  26. DWORD SectorSize;
  27. HANDLE DrvStrHandle;
  28. HANDLE ThrdHandle;
  29. ULONG BufferSize = 0,
  30. IoCount = 0,
  31. index = 0,
  32. Seconds = 0,
  33. Minutes = 0,
  34. Hours = 0,
  35. Days = 0,
  36. ElapsedTime = 0,
  37. NumberIOs = 0;
  38. BOOL RunTest = FALSE;
  39. BOOL TestFileCreated = FALSE;
  40. BOOL KillFileCreate = FALSE;
  41. PARAMS Params;
  42. FILE_PARAMS TestFileParams;
  43. HINSTANCE HInst;
  44. HWND Gauge;
  45. DWORD GaugeId;
  46. //
  47. // Thread proc. declarations
  48. //
  49. DWORD
  50. ReadSequential(
  51. PPARAMS pParams
  52. );
  53. DWORD
  54. WriteSequential(
  55. PPARAMS pParams
  56. );
  57. DWORD
  58. ReadRandom(
  59. PPARAMS pParams
  60. );
  61. DWORD
  62. WriteRandom(
  63. PPARAMS pParams
  64. );
  65. //
  66. // Common util. functions
  67. //
  68. ULONG
  69. GetRandomOffset(
  70. ULONG min,
  71. ULONG max
  72. );
  73. BOOL
  74. GetSectorSize(
  75. PDWORD SectorSize,
  76. PCHAR DrvLetter
  77. );
  78. VOID
  79. LogError(
  80. PCHAR ErrString,
  81. DWORD UniqueId,
  82. DWORD ErrCode
  83. );
  84. VOID
  85. Usage(
  86. VOID
  87. );
  88. LPTHREAD_START_ROUTINE
  89. TestProc[4] = {ReadSequential,
  90. ReadRandom,
  91. WriteSequential,
  92. WriteRandom
  93. };
  94. BOOL
  95. InitDialog (
  96. HWND hwnd,
  97. HWND hwndFocus,
  98. LPARAM lParam
  99. )
  100. {
  101. BOOLEAN Found = FALSE;
  102. CHAR buffer[34];
  103. DWORD bytes;
  104. HWND Drives = GetDlgItem (hwnd,DRV_BOX);
  105. PCHAR lp;
  106. UINT i = 0,
  107. NoDrives = 0;
  108. srand(GetTickCount());
  109. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
  110. //
  111. // Get attached drives, filter out non-disk drives, and fill drive box.
  112. //
  113. bytes = GetLogicalDriveStrings(0,NULL);
  114. DrvStrHandle = VirtualAlloc(NULL,bytes + 1,
  115. MEM_COMMIT | MEM_RESERVE,
  116. PAGE_READWRITE);
  117. GetLogicalDriveStrings( bytes, DrvStrHandle);
  118. for (lp = DrvStrHandle;*lp; ) {
  119. if (GetDriveType(lp) == DRIVE_FIXED) {
  120. ComboBox_AddString(Drives,lp);
  121. ++NoDrives;
  122. }
  123. while(*lp++);
  124. }
  125. //
  126. // Check for cmd line params passed in, and set the test drive to either
  127. // the specified drive, or to the first in the drive list.
  128. //
  129. ComboBox_SetCurSel (Drives,0);
  130. if (TestDrv[4] != '\0') {
  131. do {
  132. ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer,4);
  133. if (buffer[0] == TestDrv[4]) {
  134. Found = TRUE;
  135. } else {
  136. if (++i >= NoDrives) {
  137. Found = TRUE;
  138. } else {
  139. ComboBox_SetCurSel (Drives,i);
  140. }
  141. }
  142. } while (!Found);
  143. if (i >= NoDrives) {
  144. //
  145. // Couldn't find the drive, exit with a message.
  146. //
  147. LogError("Incorrect Drive Letter in command line.",1,0);
  148. EndDialog(hwnd,0);
  149. return FALSE;
  150. }
  151. } else {
  152. ComboBox_SetCurSel (Drives,0);
  153. }
  154. //
  155. // Get the sector size for the default selection.
  156. //
  157. TestDrv[4] = '\0';
  158. ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4);
  159. strcat (TestDrv,buffer);
  160. TestDrv[6] = '\0';
  161. GetSectorSize(&SectorSize,TestDrv);
  162. //
  163. // If index is 0, use defaults, otherwise set the test according to
  164. // the cmdline passes in.
  165. //
  166. Button_SetCheck(GetDlgItem(hwnd,TEST_RAD_READ + (index >> 1)), TRUE);
  167. Button_SetCheck(GetDlgItem(hwnd,VAR_RAD_SEQ + (index & 0x01)),TRUE);
  168. //
  169. // Set buffer size.
  170. //
  171. if (BufferSize == 0) {
  172. BufferSize = 65536;
  173. NumberIOs = FILE_SIZE / BufferSize;
  174. } else {
  175. //
  176. // Verify that buffersize is a multiple of sector size, if not adjust it.
  177. //
  178. if (BufferSize % SectorSize) {
  179. BufferSize &= ~(SectorSize - 1);
  180. }
  181. NumberIOs = FILE_SIZE / BufferSize;
  182. //
  183. // Cmd line was present and has been used to config. the test. Send a message
  184. // to the start button to get things rolling.
  185. //
  186. SendMessage(hwnd,WM_COMMAND,(BN_CLICKED << 16) | START_BUTTON,(LPARAM)GetDlgItem(hwnd,START_BUTTON));
  187. }
  188. _ultoa(BufferSize,buffer,10);
  189. Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer);
  190. return(TRUE);
  191. }
  192. DWORD
  193. CreateTestFile(
  194. PFILE_PARAMS FileParams
  195. )
  196. {
  197. PCHAR index = FileParams->TestDrive;
  198. PUCHAR buffer;
  199. CHAR errBuf[80];
  200. HANDLE file,port;
  201. OVERLAPPED overlapped,*overlapped2;
  202. DWORD bytesTransferred,bytesTransferred2;
  203. DWORD_PTR key;
  204. BOOL status;
  205. ULONG i;
  206. while (*index == '\\' || *index == '.') {
  207. index++;
  208. }
  209. strcpy(FileParams->TestFile,index);
  210. strcat(FileParams->TestFile,"\\test.dat");
  211. DeleteFile(FileParams->TestFile);
  212. buffer = VirtualAlloc(NULL,
  213. BufferSize,
  214. MEM_COMMIT,
  215. PAGE_READWRITE);
  216. if ( !buffer ) {
  217. sprintf(errBuf,"Error allocating buffer %d\n",GetLastError());
  218. MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK);
  219. ExitThread(3);
  220. return 3;
  221. }
  222. file = CreateFile(FileParams->TestFile,
  223. GENERIC_READ | GENERIC_WRITE,
  224. FILE_SHARE_READ | FILE_SHARE_WRITE,
  225. NULL,
  226. OPEN_ALWAYS,
  227. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  228. NULL );
  229. if ( file == INVALID_HANDLE_VALUE ) {
  230. sprintf(errBuf,"Error opening file %s %d\n",FileParams->TestFile,GetLastError());
  231. MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK);
  232. ExitThread(3);
  233. return 3;
  234. }
  235. port = CreateIoCompletionPort(file,
  236. NULL,
  237. (DWORD_PTR)file,
  238. 0);
  239. if ( !port ) {
  240. sprintf(errBuf,"Error creating completion port %d\n",GetLastError());
  241. MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK);
  242. return FALSE;
  243. }
  244. memset(&overlapped,0,sizeof(overlapped));
  245. for (i = 0; i < NumberIOs; i++) {
  246. //
  247. // If user aborted file create, exit.
  248. //
  249. if (KillFileCreate) {
  250. DeleteFile(FileParams->TestFile);
  251. ExitThread(4);
  252. return 4;
  253. }
  254. retryWrite:
  255. status = WriteFile(file,
  256. buffer,
  257. BufferSize,
  258. &bytesTransferred,
  259. &overlapped);
  260. if ( !status && GetLastError() != ERROR_IO_PENDING ) {
  261. if (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  262. GetLastError() == ERROR_NOT_ENOUGH_QUOTA ||
  263. GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
  264. goto retryWrite;
  265. }
  266. sprintf(errBuf,"Error creating test file %d\n",GetLastError());
  267. MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK);
  268. ExitThread(3);
  269. return 3;
  270. }
  271. //
  272. // Update gauge.
  273. //
  274. DrawMeterBar(FileParams->Window,GaugeId,i / 2,NumberIOs,FALSE);
  275. overlapped.Offset += BufferSize;
  276. }
  277. for (i = 0; i < NumberIOs; i++ ) {
  278. status = GetQueuedCompletionStatus(port,
  279. &bytesTransferred2,
  280. &key,
  281. &overlapped2,
  282. (DWORD)-1);
  283. if ( !status ) {
  284. sprintf(errBuf,"Error picking up completion pre-write %d\n",GetLastError());
  285. MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK);
  286. ExitThread(2);
  287. return 2;
  288. }
  289. DrawMeterBar(FileParams->Window,GaugeId, NumberIOs / 2 + i / 2,NumberIOs,FALSE);
  290. }
  291. CloseHandle(port);
  292. CloseHandle(file);
  293. ExitThread(1);
  294. return 1;
  295. }
  296. //
  297. // Progress gauge courtesy of wesw
  298. //
  299. VOID
  300. DrawMeterBar(
  301. HWND hwnd,
  302. DWORD ctlId,
  303. DWORD wPartsComplete,
  304. DWORD wPartsInJob,
  305. BOOL fRedraw
  306. )
  307. {
  308. RECT rcPrcnt;
  309. DWORD dwColor;
  310. SIZE size;
  311. DWORD pct;
  312. CHAR szPercentage[255];
  313. HPEN hpen;
  314. HPEN oldhpen;
  315. HDC hDC;
  316. RECT rcItem;
  317. POINT pt;
  318. hDC = GetDC( hwnd );
  319. GetWindowRect( GetDlgItem(hwnd,ctlId), &rcItem );
  320. pt.x = rcItem.left;
  321. pt.y = rcItem.top;
  322. ScreenToClient( hwnd, &pt );
  323. rcItem.left = pt.x;
  324. rcItem.top = pt.y;
  325. pt.x = rcItem.right;
  326. pt.y = rcItem.bottom;
  327. ScreenToClient( hwnd, &pt );
  328. rcItem.right = pt.x;
  329. rcItem.bottom = pt.y;
  330. hpen = CreatePen( PS_SOLID, 1, RGB(0,0,0) );
  331. if (hpen) {
  332. oldhpen = SelectObject( hDC, hpen );
  333. if (fRedraw) {
  334. Rectangle( hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom );
  335. }
  336. SelectObject( hDC, oldhpen );
  337. DeleteObject( hpen );
  338. }
  339. rcItem.left += 2;
  340. rcItem.top += 2;
  341. rcItem.right -= 2;
  342. rcItem.bottom -= 2;
  343. //
  344. // Set-up default foreground and background text colors.
  345. //
  346. SetBkColor( hDC, RGB(125,125,125) );
  347. SetTextColor( hDC, RGB(125,58,125) );
  348. SetTextAlign(hDC, TA_CENTER | TA_TOP);
  349. //
  350. // Invert the foreground and background colors.
  351. //
  352. dwColor = GetBkColor(hDC);
  353. SetBkColor(hDC, SetTextColor(hDC, dwColor));
  354. //
  355. // calculate the percentage done
  356. //
  357. try {
  358. pct = (DWORD)((float)wPartsComplete / (float)wPartsInJob * 100.0);
  359. } except(EXCEPTION_EXECUTE_HANDLER) {
  360. pct = 0;
  361. }
  362. //
  363. // Set rectangle coordinates to include only left part of the window
  364. //
  365. rcPrcnt.top = rcItem.top;
  366. rcPrcnt.bottom = rcItem.bottom;
  367. rcPrcnt.left = rcItem.left;
  368. rcPrcnt.right = rcItem.left +
  369. (DWORD)((float)(rcItem.right - rcItem.left) * ((float)pct / 100));
  370. //
  371. // Output the percentage value in the window.
  372. // Function also paints left part of window.
  373. //
  374. wsprintf(szPercentage, "%d%%", pct);
  375. GetTextExtentPoint(hDC, "X", 1, &size);
  376. ExtTextOut( hDC,
  377. (rcItem.right - rcItem.left) / 2,
  378. rcItem.top + ((rcItem.bottom - rcItem.top - size.cy) / 2),
  379. ETO_OPAQUE | ETO_CLIPPED,
  380. &rcPrcnt,
  381. szPercentage,
  382. strlen(szPercentage),
  383. NULL
  384. );
  385. //
  386. // Adjust rectangle so that it includes the remaining
  387. // percentage of the window.
  388. //
  389. rcPrcnt.left = rcPrcnt.right;
  390. rcPrcnt.right = rcItem.right;
  391. //
  392. // Invert the foreground and background colors.
  393. //
  394. dwColor = GetBkColor(hDC);
  395. SetBkColor(hDC, SetTextColor(hDC, dwColor));
  396. //
  397. // Output the percentage value a second time in the window.
  398. // Function also paints right part of window.
  399. //
  400. ExtTextOut( hDC,
  401. (rcItem.right - rcItem.left) / 2,
  402. rcItem.top + ((rcItem.bottom - rcItem.top - size.cy) / 2),
  403. ETO_OPAQUE | ETO_CLIPPED,
  404. &rcPrcnt,
  405. szPercentage,
  406. strlen(szPercentage),
  407. NULL
  408. );
  409. ReleaseDC( hwnd, hDC );
  410. return;
  411. }
  412. VOID
  413. ProcessCommands(
  414. HWND hwnd,
  415. INT id,
  416. HWND hwndCtl,
  417. UINT codeNotify)
  418. {
  419. DWORD exitCode;
  420. CHAR buffer[20];
  421. ULONG tid;
  422. ULONG units;
  423. switch (id) {
  424. case DRV_BOX:
  425. if (codeNotify == CBN_KILLFOCUS) {
  426. //
  427. // Determine sector size of chosen drive.
  428. //
  429. ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4);
  430. sprintf(TestDrv,"\\\\.\\");
  431. strcat(TestDrv,buffer);
  432. TestDrv[6] = '\0';
  433. GetSectorSize(&SectorSize,TestDrv);
  434. }
  435. break;
  436. case START_BUTTON:
  437. if (!TestFileCreated) {
  438. //
  439. // Create gauge window.
  440. //
  441. units = GetDialogBaseUnits();
  442. Gauge = CreateWindow("static","",
  443. WS_CHILD | WS_VISIBLE | SS_BLACKFRAME,
  444. (INT)(10 * (units & 0xFFFF) / 4),
  445. (INT)(60 * (units >> 16) / 8),
  446. (INT)(150 * (units & 0xFFFF) / 4),
  447. (INT)(12 * (units >> 16) / 8),
  448. hwnd,
  449. (HMENU)(26),
  450. HInst,
  451. NULL);
  452. GaugeId = GetDlgCtrlID(Gauge);
  453. TestFileParams.TestDrive = TestDrv;
  454. TestFileParams.TestFile = TestFile;
  455. TestFileParams.Window = hwnd;
  456. ThrdHandle = CreateThread (NULL,0,(LPTHREAD_START_ROUTINE)CreateTestFile, &TestFileParams,CREATE_SUSPENDED,&tid);
  457. if (ThrdHandle) {
  458. //
  459. // Disable controls
  460. //
  461. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), TRUE);
  462. SetFocus(GetDlgItem(hwnd,STOP_BUTTON));
  463. Button_Enable(GetDlgItem(hwnd,START_BUTTON), FALSE);
  464. SetTimer(hwnd,TIMER_ID2,1000,(TIMERPROC)NULL);
  465. ResumeThread(ThrdHandle);
  466. sprintf(buffer,"CREATING TEST FILE");
  467. Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
  468. }
  469. break;
  470. }
  471. //
  472. // Determine the test drive.
  473. //
  474. strcpy(TestDrv,"\\\\.\\");
  475. ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4);
  476. strcat (TestDrv,buffer);
  477. TestDrv[6] = '\0';
  478. //
  479. // Determine the test case.
  480. //
  481. index = Button_GetCheck(GetDlgItem(hwnd,TEST_RAD_WRITE));
  482. index <<= 1;
  483. index |= Button_GetCheck(GetDlgItem(hwnd,VAR_RAD_RAND));
  484. //
  485. // Update the status fields
  486. //
  487. sprintf(buffer,"%Lu",BufferSize);
  488. Static_SetText(GetDlgItem(hwnd,STATUS_BUFFER ),buffer);
  489. sprintf(buffer,"%d",IoCount);
  490. Static_SetText(GetDlgItem(hwnd,STATUS_IOCOUNT), buffer);
  491. sprintf(buffer,"%s",(index >> 1) ? "Write" : "Read");
  492. Static_SetText(GetDlgItem(hwnd,STATUS_CASE), buffer);
  493. sprintf(buffer,"%s",(index & 0x1) ? "Random" : "Sequential");
  494. Static_SetText(GetDlgItem(hwnd,STATUS_CASE1), buffer);
  495. sprintf(buffer,"RUNNING");
  496. Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
  497. ElapsedTime = Seconds = Minutes = Hours = Days = 0;
  498. SetTimer(hwnd,TIMER_ID,1000,(TIMERPROC)NULL);
  499. //
  500. // Gather parameters and launch the test.
  501. //
  502. Params.BufferSize = BufferSize;
  503. Params.TargetFile = TestFile;
  504. Params.Tcount = NumberIOs;
  505. RunTest = TRUE;
  506. //
  507. // Launch the thread.
  508. //
  509. ThrdHandle = CreateThread (NULL,
  510. 0,
  511. TestProc[index],
  512. &Params,
  513. CREATE_SUSPENDED,
  514. &tid
  515. );
  516. if (ThrdHandle)
  517. ResumeThread(ThrdHandle);
  518. //
  519. // Disable controls
  520. //
  521. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), TRUE);
  522. SetFocus(GetDlgItem(hwnd,STOP_BUTTON));
  523. Button_Enable(GetDlgItem(hwnd,START_BUTTON), FALSE);
  524. break;
  525. case STOP_BUTTON:
  526. if (!TestFileCreated) {
  527. //
  528. // Kill the test file create thread.
  529. //
  530. KillFileCreate = TRUE;
  531. WaitForSingleObject(ThrdHandle,INFINITE);
  532. //
  533. // Redo button enable/disable/focus
  534. //
  535. Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE);
  536. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
  537. SetFocus(GetDlgItem(hwnd,START_BUTTON));
  538. KillTimer(hwnd, TIMER_ID2);
  539. KillFileCreate = FALSE;
  540. sprintf(buffer,"STOPPED");
  541. Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
  542. DestroyWindow(Gauge);
  543. UpdateWindow(hwnd);
  544. break;
  545. }
  546. KillTimer(hwnd, TIMER_ID);
  547. //
  548. // If the thread is not running disregard it.
  549. //
  550. GetExitCodeThread(ThrdHandle,&exitCode);
  551. if (exitCode == STILL_ACTIVE) {
  552. //
  553. // Set flag to kill the threads.
  554. //
  555. RunTest = FALSE;
  556. if ((WaitForSingleObject (ThrdHandle,INFINITE)) == WAIT_FAILED) {
  557. //
  558. // TODO: Do something drastic.
  559. //
  560. }
  561. }
  562. //
  563. // Re-enable/disable buttons
  564. //
  565. Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE);
  566. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
  567. SetFocus(GetDlgItem(hwnd,START_BUTTON));
  568. sprintf(buffer,"STOPPED");
  569. Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
  570. break;
  571. case QUIT_BUTTON:
  572. case IDCANCEL:
  573. EndDialog(hwnd, id);
  574. break;
  575. default:
  576. break;
  577. }
  578. }
  579. VOID
  580. ProcessSpinCmds(
  581. HWND hwnd,
  582. HWND hCtl,
  583. UINT code,
  584. INT position)
  585. {
  586. CHAR buffer[34];
  587. if (hCtl == GetDlgItem(hwnd,SPIN_CTL)) {
  588. //
  589. // Get the current buffer size
  590. //
  591. Static_GetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer,sizeof(buffer));
  592. BufferSize = atol(buffer);
  593. switch (code) {
  594. case SB_PAGEDOWN:
  595. case SB_BOTTOM:
  596. case SB_LINEDOWN:
  597. if ((BufferSize -= SectorSize) < SectorSize) {
  598. BufferSize = 1048576;
  599. }
  600. NumberIOs = FILE_SIZE / BufferSize;
  601. _ultoa(BufferSize,buffer,10);
  602. Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer);
  603. break;
  604. case SB_LINEUP:
  605. case SB_PAGEUP:
  606. case SB_TOP:
  607. if ((BufferSize += SectorSize) > 1048576) {
  608. BufferSize = SectorSize;
  609. }
  610. NumberIOs = FILE_SIZE / BufferSize;
  611. _ultoa(BufferSize,buffer,10);
  612. Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer);
  613. break;
  614. case SB_THUMBPOSITION:
  615. case SB_THUMBTRACK:
  616. break;
  617. }
  618. }
  619. }
  620. VOID
  621. FormatTime(ULONG Time)
  622. {
  623. ++Seconds;
  624. if (Seconds % 60 == 0) {
  625. ++Minutes;
  626. Seconds = 0;
  627. if(Minutes % 60 == 0) {
  628. ++Hours;
  629. Minutes = 0;
  630. if(Hours % 24 == 0) {
  631. ++Days;
  632. Hours = 0;
  633. }
  634. }
  635. }
  636. sprintf(TimerText,"%02d:%02d:%02d:%02d",Days,Hours,Minutes,Seconds);
  637. }
  638. VOID
  639. ProcessTimer(
  640. HWND hwnd,
  641. UINT id)
  642. {
  643. CHAR buffer[40];
  644. if (id == TIMER_ID) {
  645. ++ElapsedTime;
  646. FormatTime (ElapsedTime);
  647. SetWindowText(GetDlgItem(hwnd,TIME_TEXT),TimerText);
  648. } else if (id == TIMER_ID2) {
  649. //
  650. // Get status of file create thread.
  651. //
  652. if ( WaitForSingleObject (ThrdHandle,0) == WAIT_OBJECT_0) {
  653. TestFileCreated = TRUE;
  654. KillTimer(hwnd, TIMER_ID2);
  655. DestroyWindow(Gauge);
  656. UpdateWindow(hwnd);
  657. //
  658. // Redo controls
  659. //
  660. Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE);
  661. Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
  662. SetFocus(GetDlgItem(hwnd,START_BUTTON));
  663. sprintf(buffer,"READY");
  664. Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
  665. }
  666. }
  667. }
  668. INT_PTR
  669. CALLBACK
  670. BenchDlgProc(
  671. HWND hDlg,
  672. UINT uMsg,
  673. WPARAM wParam,
  674. LPARAM lParam
  675. )
  676. {
  677. BOOL Processed = TRUE;
  678. switch (uMsg) {
  679. HANDLE_MSG(hDlg, WM_INITDIALOG, InitDialog);
  680. HANDLE_MSG(hDlg, WM_COMMAND, ProcessCommands);
  681. HANDLE_MSG(hDlg, WM_VSCROLL, ProcessSpinCmds);
  682. HANDLE_MSG(hDlg, WM_TIMER, ProcessTimer);
  683. default:
  684. Processed = FALSE;
  685. break;
  686. }
  687. return Processed;
  688. }
  689. INT APIENTRY
  690. WinMain(
  691. HINSTANCE hInstance,
  692. HINSTANCE hPrevInstance,
  693. LPSTR CmdLine,
  694. INT CmdShow)
  695. {
  696. CHAR buffer[10];
  697. PCHAR tmp = buffer,
  698. cmdLinePtr,
  699. ptr;
  700. //
  701. // Check for, and process cmd line.
  702. //
  703. HInst = hInstance;
  704. cmdLinePtr = CmdLine;
  705. if (*cmdLinePtr != '\0') {
  706. while (*cmdLinePtr != '\0') {
  707. tmp = buffer;
  708. memset (tmp,0,sizeof(buffer));
  709. if (*cmdLinePtr == '-') {
  710. switch (*(cmdLinePtr + 1)) {
  711. case 'b':
  712. case 'B':
  713. ptr = cmdLinePtr + 2;
  714. while (*ptr != ' ') {
  715. *tmp++ = *ptr++;
  716. }
  717. BufferSize = 1024 * atol(buffer);
  718. cmdLinePtr = ptr;
  719. while (*cmdLinePtr++ == ' ');
  720. --cmdLinePtr;
  721. break;
  722. case 't':
  723. case 'T':
  724. ptr = cmdLinePtr + 2;
  725. if (*ptr != 'r' && *ptr != 'R' && *ptr != 'w' && *ptr != 'W') {
  726. Usage();
  727. return 1;
  728. }
  729. index = (*ptr == 'R' || *ptr == 'r') ? 0 : 1;
  730. ++ptr;
  731. if (*ptr != 's' && *ptr != 'S' && *ptr != 'r' && *ptr != 'R') {
  732. Usage();
  733. return 1;
  734. }
  735. index <<= 1;
  736. index |= (*ptr == 'S' || *ptr == 's') ? 0 : 1;
  737. ++ptr;
  738. cmdLinePtr = ptr;
  739. while (*cmdLinePtr++ == ' ');
  740. --cmdLinePtr;
  741. break;
  742. default:
  743. Usage();
  744. return 1;
  745. }
  746. } else if (*(cmdLinePtr + 1) == ':') {
  747. sprintf (buffer,"%c%c%c",toupper(*cmdLinePtr),':','\\');
  748. strcat (TestDrv,buffer);
  749. while (*cmdLinePtr++ != ' ');
  750. while (*cmdLinePtr++ == ' ');
  751. --cmdLinePtr;
  752. } else {
  753. Usage();
  754. return 1;
  755. }
  756. }
  757. }
  758. DialogBox(hInstance, MAKEINTRESOURCE(BENCH_DLG), NULL, BenchDlgProc);
  759. return(0);
  760. }
  761. DWORD
  762. ReadSequential(
  763. PPARAMS Params
  764. )
  765. {
  766. ULONG j,
  767. errCode,
  768. outstandingRequests;
  769. HANDLE file,
  770. port;
  771. OVERLAPPED overlapped,
  772. *overlapped2;
  773. DWORD bytesRead,
  774. bytesRead2,
  775. version;
  776. DWORD_PTR completionKey;
  777. BOOL status;
  778. PUCHAR buffer;
  779. version = GetVersion() >> 16;
  780. buffer = VirtualAlloc(NULL,
  781. Params->BufferSize + SectorSize - 1,
  782. MEM_COMMIT | MEM_RESERVE,
  783. PAGE_READWRITE);
  784. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  785. if ( !buffer ) {
  786. LogError("Error allocating buffer",1,GetLastError());
  787. ExitThread(1);
  788. return 2;
  789. }
  790. while (RunTest) {
  791. file = CreateFile(Params->TargetFile,
  792. GENERIC_READ | GENERIC_WRITE,
  793. FILE_SHARE_READ | FILE_SHARE_WRITE,
  794. NULL,
  795. OPEN_ALWAYS,
  796. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  797. NULL );
  798. if ( file == INVALID_HANDLE_VALUE ) {
  799. LogError("Error opening Target file",2,GetLastError());
  800. VirtualFree(buffer,
  801. Params->BufferSize + SectorSize - 1,
  802. MEM_DECOMMIT);
  803. ExitThread(2);
  804. return 2;
  805. }
  806. port = CreateIoCompletionPort(file,
  807. NULL,
  808. (DWORD_PTR)file,
  809. 0);
  810. if ( !port ) {
  811. LogError("Error creating completion port",3,GetLastError());
  812. VirtualFree(buffer,
  813. Params->BufferSize + SectorSize - 1,
  814. MEM_DECOMMIT);
  815. ExitThread(3);
  816. return 3;
  817. }
  818. memset(&overlapped,0,sizeof(overlapped));
  819. outstandingRequests = 0;
  820. for (j = 0; j < Params->Tcount; j++) {
  821. do {
  822. status = ReadFile(file,
  823. buffer,
  824. Params->BufferSize,
  825. &bytesRead,
  826. &overlapped);
  827. errCode = GetLastError();
  828. if (!status) {
  829. if (errCode == ERROR_IO_PENDING) {
  830. break;
  831. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  832. errCode == ERROR_INVALID_USER_BUFFER ||
  833. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  834. //
  835. // Allow this to retry.
  836. //
  837. } else {
  838. LogError("Error in ReadFile",4,errCode);
  839. VirtualFree(buffer,
  840. Params->BufferSize + SectorSize - 1,
  841. MEM_DECOMMIT);
  842. ExitThread(4);
  843. return 4;
  844. }
  845. }
  846. } while (!status);
  847. outstandingRequests++;
  848. overlapped.Offset += Params->BufferSize;
  849. }
  850. for (j = 0; j < outstandingRequests; j++) {
  851. status = GetQueuedCompletionStatus(port,
  852. &bytesRead2,
  853. &completionKey,
  854. &overlapped2,
  855. (DWORD)-1);
  856. if (!status) {
  857. LogError("GetQueuedCompletionStatus error.",5,GetLastError());
  858. VirtualFree(buffer,
  859. Params->BufferSize + SectorSize - 1,
  860. MEM_DECOMMIT);
  861. ExitThread(5);
  862. return 5;
  863. }
  864. }
  865. if (version > 612) {
  866. CloseHandle(port);
  867. }
  868. CloseHandle(file);
  869. }
  870. VirtualFree(buffer,
  871. Params->BufferSize + SectorSize - 1,
  872. MEM_DECOMMIT);
  873. ExitThread(0);
  874. return 0;
  875. }
  876. DWORD
  877. WriteSequential(
  878. PPARAMS Params
  879. )
  880. {
  881. ULONG j,
  882. errCode,
  883. outstandingRequests;
  884. HANDLE file,
  885. port;
  886. OVERLAPPED overlapped,
  887. *overlapped2;
  888. DWORD bytesWrite,
  889. bytesWrite2,
  890. version;
  891. DWORD_PTR completionKey;
  892. BOOL status;
  893. PUCHAR buffer;
  894. version = GetVersion() >> 16;
  895. buffer = VirtualAlloc(NULL,
  896. Params->BufferSize + SectorSize - 1,
  897. MEM_COMMIT | MEM_RESERVE,
  898. PAGE_READWRITE);
  899. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  900. if ( !buffer ) {
  901. LogError("Error allocating buffer",1,GetLastError());
  902. ExitThread(1);
  903. return 2;
  904. }
  905. while (RunTest) {
  906. file = CreateFile(Params->TargetFile,
  907. GENERIC_READ | GENERIC_WRITE,
  908. FILE_SHARE_READ | FILE_SHARE_WRITE,
  909. NULL,
  910. OPEN_ALWAYS,
  911. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  912. NULL );
  913. if ( file == INVALID_HANDLE_VALUE ) {
  914. LogError("Error opening Target file",2,GetLastError());
  915. VirtualFree(buffer,
  916. Params->BufferSize + SectorSize - 1,
  917. MEM_DECOMMIT);
  918. ExitThread(2);
  919. return 2;
  920. }
  921. port = CreateIoCompletionPort(file,
  922. NULL,
  923. (DWORD_PTR)file,
  924. 0);
  925. if ( !port ) {
  926. LogError("Error creating completion port",3,GetLastError());
  927. VirtualFree(buffer,
  928. Params->BufferSize + SectorSize - 1,
  929. MEM_DECOMMIT);
  930. ExitThread(3);
  931. return 3;
  932. }
  933. memset(&overlapped,0,sizeof(overlapped));
  934. outstandingRequests = 0;
  935. for (j = 0; j < Params->Tcount; j++) {
  936. do {
  937. status = WriteFile(file,
  938. buffer,
  939. Params->BufferSize,
  940. &bytesWrite,
  941. &overlapped);
  942. errCode = GetLastError();
  943. if (!status) {
  944. if (errCode == ERROR_IO_PENDING) {
  945. break;
  946. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  947. errCode == ERROR_INVALID_USER_BUFFER ||
  948. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  949. //
  950. // Allow this to retry.
  951. //
  952. } else {
  953. LogError("Error in WriteFile",4,errCode);
  954. VirtualFree(buffer,
  955. Params->BufferSize + SectorSize - 1,
  956. MEM_DECOMMIT);
  957. ExitThread(4);
  958. return 4;
  959. }
  960. }
  961. } while (!status);
  962. outstandingRequests++;
  963. overlapped.Offset += Params->BufferSize;
  964. }
  965. for (j = 0; j < outstandingRequests; j++) {
  966. status = GetQueuedCompletionStatus(port,
  967. &bytesWrite2,
  968. &completionKey,
  969. &overlapped2,
  970. (DWORD)-1);
  971. if (!status) {
  972. LogError("GetQueuedCompletionStatus error.",5,GetLastError());
  973. VirtualFree(buffer,
  974. Params->BufferSize + SectorSize - 1,
  975. MEM_DECOMMIT);
  976. ExitThread(5);
  977. return 5;
  978. }
  979. }
  980. if (version > 612) {
  981. CloseHandle(port);
  982. }
  983. CloseHandle(file);
  984. }
  985. VirtualFree(buffer,
  986. Params->BufferSize + SectorSize - 1,
  987. MEM_DECOMMIT);
  988. ExitThread(0);
  989. return 0;
  990. }
  991. DWORD
  992. ReadRandom(
  993. PPARAMS Params
  994. )
  995. {
  996. ULONG j,
  997. errCode,
  998. outstandingRequests;
  999. HANDLE file,
  1000. port;
  1001. OVERLAPPED overlapped,
  1002. *overlapped2;
  1003. DWORD bytesRead,
  1004. bytesRead2,
  1005. version;
  1006. DWORD_PTR completionKey;
  1007. BOOL status;
  1008. PUCHAR buffer;
  1009. version = GetVersion() >> 16;
  1010. buffer = VirtualAlloc(NULL,
  1011. Params->BufferSize + SectorSize - 1,
  1012. MEM_COMMIT | MEM_RESERVE,
  1013. PAGE_READWRITE);
  1014. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  1015. if ( !buffer ) {
  1016. LogError("Error allocating buffer",1,GetLastError());
  1017. ExitThread(1);
  1018. return 2;
  1019. }
  1020. while (RunTest) {
  1021. file = CreateFile(Params->TargetFile,
  1022. GENERIC_READ | GENERIC_WRITE,
  1023. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1024. NULL,
  1025. OPEN_ALWAYS,
  1026. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  1027. NULL );
  1028. if ( file == INVALID_HANDLE_VALUE ) {
  1029. LogError("Error opening Target file",2,GetLastError());
  1030. VirtualFree(buffer,
  1031. Params->BufferSize + SectorSize - 1,
  1032. MEM_DECOMMIT);
  1033. ExitThread(2);
  1034. return 2;
  1035. }
  1036. port = CreateIoCompletionPort(file,
  1037. NULL,
  1038. (DWORD_PTR)file,
  1039. 0);
  1040. if ( !port ) {
  1041. LogError("Error creating completion port",3,GetLastError());
  1042. VirtualFree(buffer,
  1043. Params->BufferSize + SectorSize - 1,
  1044. MEM_DECOMMIT);
  1045. ExitThread(3);
  1046. return 3;
  1047. }
  1048. memset(&overlapped,0,sizeof(overlapped));
  1049. outstandingRequests = 0;
  1050. for (j = 0; j < Params->Tcount; j++) {
  1051. do {
  1052. status = ReadFile(file,
  1053. buffer,
  1054. Params->BufferSize,
  1055. &bytesRead,
  1056. &overlapped);
  1057. errCode = GetLastError();
  1058. if (!status) {
  1059. if (errCode == ERROR_IO_PENDING) {
  1060. break;
  1061. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  1062. errCode == ERROR_INVALID_USER_BUFFER ||
  1063. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  1064. //
  1065. // Allow this to retry.
  1066. //
  1067. } else {
  1068. LogError("Error in ReadFile",4,errCode);
  1069. VirtualFree(buffer,
  1070. Params->BufferSize + SectorSize - 1,
  1071. MEM_DECOMMIT);
  1072. ExitThread(4);
  1073. return 4;
  1074. }
  1075. }
  1076. } while (!status);
  1077. outstandingRequests++;
  1078. overlapped.Offset = GetRandomOffset(0,FILE_SIZE - Params->BufferSize);
  1079. }
  1080. for (j = 0; j < outstandingRequests; j++) {
  1081. status = GetQueuedCompletionStatus(port,
  1082. &bytesRead2,
  1083. &completionKey,
  1084. &overlapped2,
  1085. (DWORD)-1);
  1086. if (!status) {
  1087. LogError("GetQueuedCompletionStatus error.",5,GetLastError());
  1088. VirtualFree(buffer,
  1089. Params->BufferSize + SectorSize - 1,
  1090. MEM_DECOMMIT);
  1091. ExitThread(5);
  1092. return 5;
  1093. }
  1094. }
  1095. if (version > 612) {
  1096. CloseHandle(port);
  1097. }
  1098. CloseHandle(file);
  1099. }
  1100. VirtualFree(buffer,
  1101. Params->BufferSize + SectorSize - 1,
  1102. MEM_DECOMMIT);
  1103. ExitThread(0);
  1104. return 0;
  1105. }
  1106. DWORD
  1107. WriteRandom(
  1108. PPARAMS Params
  1109. )
  1110. {
  1111. ULONG j,
  1112. errCode,
  1113. outstandingRequests;
  1114. HANDLE file,
  1115. port;
  1116. OVERLAPPED overlapped,
  1117. *overlapped2;
  1118. DWORD bytesWrite,
  1119. bytesWrite2,
  1120. version;
  1121. DWORD_PTR completionKey;
  1122. BOOL status;
  1123. PUCHAR buffer;
  1124. version = GetVersion() >> 16;
  1125. buffer = VirtualAlloc(NULL,
  1126. Params->BufferSize + SectorSize - 1,
  1127. MEM_COMMIT | MEM_RESERVE,
  1128. PAGE_READWRITE);
  1129. (ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
  1130. if ( !buffer ) {
  1131. LogError("Error allocating buffer",1,GetLastError());
  1132. ExitThread(1);
  1133. return 2;
  1134. }
  1135. while (RunTest) {
  1136. file = CreateFile(Params->TargetFile,
  1137. GENERIC_READ | GENERIC_WRITE,
  1138. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1139. NULL,
  1140. OPEN_ALWAYS,
  1141. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  1142. NULL );
  1143. if ( file == INVALID_HANDLE_VALUE ) {
  1144. LogError("Error opening Target file",2,GetLastError());
  1145. VirtualFree(buffer,
  1146. Params->BufferSize + SectorSize - 1,
  1147. MEM_DECOMMIT);
  1148. ExitThread(2);
  1149. return 2;
  1150. }
  1151. port = CreateIoCompletionPort(file,
  1152. NULL,
  1153. (DWORD_PTR)file,
  1154. 0);
  1155. if ( !port ) {
  1156. LogError("Error creating completion port",3,GetLastError());
  1157. VirtualFree(buffer,
  1158. Params->BufferSize + SectorSize - 1,
  1159. MEM_DECOMMIT);
  1160. ExitThread(3);
  1161. return 3;
  1162. }
  1163. memset(&overlapped,0,sizeof(overlapped));
  1164. outstandingRequests = 0;
  1165. for (j = 0; j < Params->Tcount; j++) {
  1166. do {
  1167. status = WriteFile(file,
  1168. buffer,
  1169. Params->BufferSize,
  1170. &bytesWrite,
  1171. &overlapped);
  1172. errCode = GetLastError();
  1173. if (!status) {
  1174. if (errCode == ERROR_IO_PENDING) {
  1175. break;
  1176. } else if (errCode == ERROR_NOT_ENOUGH_QUOTA ||
  1177. errCode == ERROR_INVALID_USER_BUFFER ||
  1178. errCode == ERROR_NOT_ENOUGH_MEMORY) {
  1179. //
  1180. // Allow this to retry.
  1181. //
  1182. } else {
  1183. LogError("Error in WriteFile",4,errCode);
  1184. VirtualFree(buffer,
  1185. Params->BufferSize + SectorSize - 1,
  1186. MEM_DECOMMIT);
  1187. ExitThread(4);
  1188. return 4;
  1189. }
  1190. }
  1191. } while (!status);
  1192. outstandingRequests++;
  1193. overlapped.Offset = GetRandomOffset(0,FILE_SIZE - Params->BufferSize);
  1194. }
  1195. for (j = 0; j < outstandingRequests; j++) {
  1196. status = GetQueuedCompletionStatus(port,
  1197. &bytesWrite2,
  1198. &completionKey,
  1199. &overlapped2,
  1200. (DWORD)-1);
  1201. if (!status) {
  1202. LogError("GetQueuedCompletionStatus error.",5,GetLastError());
  1203. VirtualFree(buffer,
  1204. Params->BufferSize + SectorSize - 1,
  1205. MEM_DECOMMIT);
  1206. ExitThread(5);
  1207. return 5;
  1208. }
  1209. }
  1210. if (version > 612) {
  1211. CloseHandle(port);
  1212. }
  1213. CloseHandle(file);
  1214. }
  1215. VirtualFree(buffer,
  1216. Params->BufferSize + SectorSize - 1,
  1217. MEM_DECOMMIT);
  1218. ExitThread(0);
  1219. return 0;
  1220. }
  1221. ULONG
  1222. GetRandomOffset(
  1223. ULONG min,
  1224. ULONG max
  1225. )
  1226. {
  1227. INT base = rand();
  1228. ULONG retval = ((max - min) / RAND_MAX) * base;
  1229. retval += SectorSize -1;
  1230. retval &= ~(SectorSize - 1);
  1231. if (retval < min) {
  1232. return min;
  1233. } else if (retval > max ){
  1234. return max & ~(SectorSize - 1);
  1235. } else{
  1236. return retval;
  1237. }
  1238. }
  1239. VOID
  1240. LogError(
  1241. PCHAR ErrString,
  1242. DWORD UniqueId,
  1243. DWORD ErrCode
  1244. )
  1245. {
  1246. CHAR ErrBuf[80];
  1247. #if DBG
  1248. sprintf(ErrBuf,"%d: %s WinError %d",UniqueId,ErrString,ErrCode);
  1249. MessageBox(NULL,ErrBuf,"Error",MB_OK | MB_ICONEXCLAMATION);
  1250. #else
  1251. return;
  1252. #endif
  1253. }
  1254. BOOL
  1255. GetSectorSize(
  1256. PDWORD SectorSize,
  1257. PCHAR DrvLetter
  1258. )
  1259. {
  1260. DISK_GEOMETRY DiskGeometry;
  1261. DWORD BytesReturned;
  1262. HANDLE handle;
  1263. handle = CreateFile(DrvLetter,
  1264. GENERIC_READ,
  1265. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1266. NULL,
  1267. OPEN_EXISTING,
  1268. FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
  1269. NULL
  1270. );
  1271. if (handle == INVALID_HANDLE_VALUE) {
  1272. return FALSE;
  1273. }
  1274. //
  1275. // Starting offset and sectors
  1276. //
  1277. if (!DeviceIoControl (handle,
  1278. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1279. NULL,
  1280. 0,
  1281. &DiskGeometry,
  1282. sizeof(DISK_GEOMETRY),
  1283. &BytesReturned,
  1284. NULL
  1285. )) {
  1286. return FALSE;
  1287. }
  1288. *SectorSize = DiskGeometry.BytesPerSector;
  1289. return TRUE;
  1290. }
  1291. VOID
  1292. Usage(
  1293. VOID
  1294. )
  1295. {
  1296. CHAR buffer[255];
  1297. sprintf(buffer,"\nDSKBENCH: V1.0\n\n");
  1298. strcat (buffer,"Usage: DSKBENCH\n");
  1299. strcat (buffer,"\t[Drvletter:]\n\t[-b] Buffer size in 1kb increments.\n\t[-tXX] Test specifier.");
  1300. strcat (buffer,"\n\tWhere XX is:\n\t\t'RS' - Read sequential.\n\t\t'RR' - Read Random\n\t\t");
  1301. strcat (buffer,"'WS' - Write sequential\n\t\t'WR' - Write Random\n\n");
  1302. strcat (buffer,"Example: Dskbench d: -b64 -tRS\n");
  1303. MessageBox(NULL,buffer,"Usage",MB_OK);
  1304. }
  1305.