Windows NT 4.0 source code leak
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

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