|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
diskmon.c
Abstract:
This module contians the code for the disk monitor utility.
Author:
Chuck Park (chuckp) 15-Feb-1994 Mike Glass (mglass)
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntdddisk.h>
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "dskbench.h"
CHAR TestDrv[8] = "\\\\.\\"; CHAR TestFile[MAX_PATH]; CHAR TimerText[] = "00:00:00:00"; DWORD SectorSize; HANDLE DrvStrHandle;
HANDLE ThrdHandle; ULONG BufferSize = 0, IoCount = 0, index = 0, Seconds = 0, Minutes = 0, Hours = 0, Days = 0, ElapsedTime = 0, NumberIOs = 0;
BOOL RunTest = FALSE; BOOL TestFileCreated = FALSE; BOOL KillFileCreate = FALSE;
PARAMS Params; FILE_PARAMS TestFileParams;
HINSTANCE HInst; HWND Gauge; DWORD GaugeId;
//
// Thread proc. declarations
//
DWORD ReadSequential( PPARAMS pParams );
DWORD WriteSequential( PPARAMS pParams );
DWORD ReadRandom( PPARAMS pParams );
DWORD WriteRandom( PPARAMS pParams );
//
// Common util. functions
//
ULONG GetRandomOffset( ULONG min, ULONG max );
BOOL GetSectorSize( PDWORD SectorSize, PCHAR DrvLetter );
VOID LogError( PCHAR ErrString, DWORD UniqueId, DWORD ErrCode );
VOID Usage( VOID );
LPTHREAD_START_ROUTINE TestProc[4] = {ReadSequential, ReadRandom, WriteSequential, WriteRandom };
BOOL InitDialog ( HWND hwnd, HWND hwndFocus, LPARAM lParam ) { BOOLEAN Found = FALSE; CHAR buffer[34]; DWORD bytes; HWND Drives = GetDlgItem (hwnd,DRV_BOX); PCHAR lp; UINT i = 0, NoDrives = 0;
srand(GetTickCount()); Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
//
// Get attached drives, filter out non-disk drives, and fill drive box.
//
bytes = GetLogicalDriveStrings(0,NULL);
DrvStrHandle = VirtualAlloc(NULL,bytes + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
GetLogicalDriveStrings( bytes, DrvStrHandle); for (lp = DrvStrHandle;*lp; ) { if (GetDriveType(lp) == DRIVE_FIXED) { ComboBox_AddString(Drives,lp); ++NoDrives; } while(*lp++); }
//
// Check for cmd line params passed in, and set the test drive to either
// the specified drive, or to the first in the drive list.
//
ComboBox_SetCurSel (Drives,0); if (TestDrv[4] != '\0') { do { ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer,4); if (buffer[0] == TestDrv[4]) { Found = TRUE; } else { if (++i >= NoDrives) { Found = TRUE; } else { ComboBox_SetCurSel (Drives,i); } } } while (!Found); if (i >= NoDrives) {
//
// Couldn't find the drive, exit with a message.
//
LogError("Incorrect Drive Letter in command line.",1,0); EndDialog(hwnd,0); return FALSE; }
} else { ComboBox_SetCurSel (Drives,0); }
//
// Get the sector size for the default selection.
//
TestDrv[4] = '\0'; ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4); strcat (TestDrv,buffer); TestDrv[6] = '\0'; GetSectorSize(&SectorSize,TestDrv);
//
// If index is 0, use defaults, otherwise set the test according to
// the cmdline passes in.
//
Button_SetCheck(GetDlgItem(hwnd,TEST_RAD_READ + (index >> 1)), TRUE); Button_SetCheck(GetDlgItem(hwnd,VAR_RAD_SEQ + (index & 0x01)),TRUE);
//
// Set buffer size.
//
if (BufferSize == 0) {
BufferSize = 65536; NumberIOs = FILE_SIZE / BufferSize;
} else {
//
// Verify that buffersize is a multiple of sector size, if not adjust it.
//
if (BufferSize % SectorSize) { BufferSize &= ~(SectorSize - 1); }
NumberIOs = FILE_SIZE / BufferSize;
//
// Cmd line was present and has been used to config. the test. Send a message
// to the start button to get things rolling.
//
SendMessage(hwnd,WM_COMMAND,(BN_CLICKED << 16) | START_BUTTON,(LPARAM)GetDlgItem(hwnd,START_BUTTON)); } _ultoa(BufferSize,buffer,10); Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer);
return(TRUE); }
DWORD CreateTestFile( PFILE_PARAMS FileParams ) { PCHAR index = FileParams->TestDrive; PUCHAR buffer; CHAR errBuf[80]; HANDLE file,port; OVERLAPPED overlapped,*overlapped2; DWORD bytesTransferred,bytesTransferred2; DWORD_PTR key; BOOL status; ULONG i;
while (*index == '\\' || *index == '.') { index++; }
strcpy(FileParams->TestFile,index); strcat(FileParams->TestFile,"\\test.dat"); DeleteFile(FileParams->TestFile);
buffer = VirtualAlloc(NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE);
if ( !buffer ) { sprintf(errBuf,"Error allocating buffer %d\n",GetLastError()); MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK); ExitThread(3); return 3; }
file = CreateFile(FileParams->TestFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL );
if ( file == INVALID_HANDLE_VALUE ) { sprintf(errBuf,"Error opening file %s %d\n",FileParams->TestFile,GetLastError()); MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK); ExitThread(3); return 3; }
port = CreateIoCompletionPort(file, NULL, (DWORD_PTR)file, 0); if ( !port ) { sprintf(errBuf,"Error creating completion port %d\n",GetLastError()); MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK); return FALSE; }
memset(&overlapped,0,sizeof(overlapped));
for (i = 0; i < NumberIOs; i++) {
//
// If user aborted file create, exit.
//
if (KillFileCreate) {
DeleteFile(FileParams->TestFile);
ExitThread(4); return 4; }
retryWrite: status = WriteFile(file, buffer, BufferSize, &bytesTransferred, &overlapped);
if ( !status && GetLastError() != ERROR_IO_PENDING ) { if (GetLastError() == ERROR_INVALID_USER_BUFFER || GetLastError() == ERROR_NOT_ENOUGH_QUOTA || GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
goto retryWrite; } sprintf(errBuf,"Error creating test file %d\n",GetLastError()); MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK); ExitThread(3); return 3; }
//
// Update gauge.
//
DrawMeterBar(FileParams->Window,GaugeId,i / 2,NumberIOs,FALSE);
overlapped.Offset += BufferSize; }
for (i = 0; i < NumberIOs; i++ ) { status = GetQueuedCompletionStatus(port, &bytesTransferred2, &key, &overlapped2, (DWORD)-1); if ( !status ) { sprintf(errBuf,"Error picking up completion pre-write %d\n",GetLastError()); MessageBox(NULL,errBuf,"Error",MB_ICONEXCLAMATION|MB_OK); ExitThread(2); return 2; }
DrawMeterBar(FileParams->Window,GaugeId, NumberIOs / 2 + i / 2,NumberIOs,FALSE); }
CloseHandle(port); CloseHandle(file);
ExitThread(1); return 1; }
//
// Progress gauge courtesy of wesw
//
VOID DrawMeterBar( HWND hwnd, DWORD ctlId, DWORD wPartsComplete, DWORD wPartsInJob, BOOL fRedraw ) { RECT rcPrcnt; DWORD dwColor; SIZE size; DWORD pct; CHAR szPercentage[255]; HPEN hpen; HPEN oldhpen; HDC hDC; RECT rcItem; POINT pt;
hDC = GetDC( hwnd );
GetWindowRect( GetDlgItem(hwnd,ctlId), &rcItem );
pt.x = rcItem.left; pt.y = rcItem.top; ScreenToClient( hwnd, &pt ); rcItem.left = pt.x; rcItem.top = pt.y;
pt.x = rcItem.right; pt.y = rcItem.bottom; ScreenToClient( hwnd, &pt ); rcItem.right = pt.x; rcItem.bottom = pt.y;
hpen = CreatePen( PS_SOLID, 1, RGB(0,0,0) ); if (hpen) { oldhpen = SelectObject( hDC, hpen ); if (fRedraw) { Rectangle( hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom ); } SelectObject( hDC, oldhpen ); DeleteObject( hpen ); } rcItem.left += 2; rcItem.top += 2; rcItem.right -= 2; rcItem.bottom -= 2;
//
// Set-up default foreground and background text colors.
//
SetBkColor( hDC, RGB(125,125,125) ); SetTextColor( hDC, RGB(125,58,125) );
SetTextAlign(hDC, TA_CENTER | TA_TOP);
//
// Invert the foreground and background colors.
//
dwColor = GetBkColor(hDC); SetBkColor(hDC, SetTextColor(hDC, dwColor));
//
// calculate the percentage done
//
try { pct = (DWORD)((float)wPartsComplete / (float)wPartsInJob * 100.0); } except(EXCEPTION_EXECUTE_HANDLER) { pct = 0; }
//
// Set rectangle coordinates to include only left part of the window
//
rcPrcnt.top = rcItem.top; rcPrcnt.bottom = rcItem.bottom; rcPrcnt.left = rcItem.left; rcPrcnt.right = rcItem.left + (DWORD)((float)(rcItem.right - rcItem.left) * ((float)pct / 100));
//
// Output the percentage value in the window.
// Function also paints left part of window.
//
wsprintf(szPercentage, "%d%%", pct); GetTextExtentPoint(hDC, "X", 1, &size); ExtTextOut( hDC, (rcItem.right - rcItem.left) / 2, rcItem.top + ((rcItem.bottom - rcItem.top - size.cy) / 2), ETO_OPAQUE | ETO_CLIPPED, &rcPrcnt, szPercentage, strlen(szPercentage), NULL );
//
// Adjust rectangle so that it includes the remaining
// percentage of the window.
//
rcPrcnt.left = rcPrcnt.right; rcPrcnt.right = rcItem.right;
//
// Invert the foreground and background colors.
//
dwColor = GetBkColor(hDC); SetBkColor(hDC, SetTextColor(hDC, dwColor));
//
// Output the percentage value a second time in the window.
// Function also paints right part of window.
//
ExtTextOut( hDC, (rcItem.right - rcItem.left) / 2, rcItem.top + ((rcItem.bottom - rcItem.top - size.cy) / 2), ETO_OPAQUE | ETO_CLIPPED, &rcPrcnt, szPercentage, strlen(szPercentage), NULL ); ReleaseDC( hwnd, hDC ); return; }
VOID ProcessCommands( HWND hwnd, INT id, HWND hwndCtl, UINT codeNotify) { DWORD exitCode; CHAR buffer[20]; ULONG tid; ULONG units;
switch (id) { case DRV_BOX: if (codeNotify == CBN_KILLFOCUS) {
//
// Determine sector size of chosen drive.
//
ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4); sprintf(TestDrv,"\\\\.\\"); strcat(TestDrv,buffer); TestDrv[6] = '\0'; GetSectorSize(&SectorSize,TestDrv);
}
break;
case START_BUTTON:
if (!TestFileCreated) {
//
// Create gauge window.
//
units = GetDialogBaseUnits();
Gauge = CreateWindow("static","", WS_CHILD | WS_VISIBLE | SS_BLACKFRAME, (INT)(10 * (units & 0xFFFF) / 4), (INT)(60 * (units >> 16) / 8), (INT)(150 * (units & 0xFFFF) / 4), (INT)(12 * (units >> 16) / 8), hwnd, (HMENU)(26), HInst, NULL);
GaugeId = GetDlgCtrlID(Gauge);
TestFileParams.TestDrive = TestDrv; TestFileParams.TestFile = TestFile; TestFileParams.Window = hwnd;
ThrdHandle = CreateThread (NULL,0,(LPTHREAD_START_ROUTINE)CreateTestFile, &TestFileParams,CREATE_SUSPENDED,&tid); if (ThrdHandle) {
//
// Disable controls
//
Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), TRUE); SetFocus(GetDlgItem(hwnd,STOP_BUTTON)); Button_Enable(GetDlgItem(hwnd,START_BUTTON), FALSE);
SetTimer(hwnd,TIMER_ID2,1000,(TIMERPROC)NULL);
ResumeThread(ThrdHandle);
sprintf(buffer,"CREATING TEST FILE"); Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer); }
break; }
//
// Determine the test drive.
//
strcpy(TestDrv,"\\\\.\\"); ComboBox_GetText(GetDlgItem(hwnd,DRV_BOX),buffer, 4); strcat (TestDrv,buffer); TestDrv[6] = '\0';
//
// Determine the test case.
//
index = Button_GetCheck(GetDlgItem(hwnd,TEST_RAD_WRITE)); index <<= 1; index |= Button_GetCheck(GetDlgItem(hwnd,VAR_RAD_RAND));
//
// Update the status fields
//
sprintf(buffer,"%Lu",BufferSize); Static_SetText(GetDlgItem(hwnd,STATUS_BUFFER ),buffer); sprintf(buffer,"%d",IoCount); Static_SetText(GetDlgItem(hwnd,STATUS_IOCOUNT), buffer);
sprintf(buffer,"%s",(index >> 1) ? "Write" : "Read"); Static_SetText(GetDlgItem(hwnd,STATUS_CASE), buffer);
sprintf(buffer,"%s",(index & 0x1) ? "Random" : "Sequential"); Static_SetText(GetDlgItem(hwnd,STATUS_CASE1), buffer);
sprintf(buffer,"RUNNING"); Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
ElapsedTime = Seconds = Minutes = Hours = Days = 0; SetTimer(hwnd,TIMER_ID,1000,(TIMERPROC)NULL);
//
// Gather parameters and launch the test.
//
Params.BufferSize = BufferSize; Params.TargetFile = TestFile; Params.Tcount = NumberIOs;
RunTest = TRUE;
//
// Launch the thread.
//
ThrdHandle = CreateThread (NULL, 0, TestProc[index], &Params, CREATE_SUSPENDED, &tid ); if (ThrdHandle) ResumeThread(ThrdHandle);
//
// Disable controls
//
Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), TRUE); SetFocus(GetDlgItem(hwnd,STOP_BUTTON)); Button_Enable(GetDlgItem(hwnd,START_BUTTON), FALSE);
break;
case STOP_BUTTON:
if (!TestFileCreated) {
//
// Kill the test file create thread.
//
KillFileCreate = TRUE;
WaitForSingleObject(ThrdHandle,INFINITE);
//
// Redo button enable/disable/focus
//
Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE); Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
SetFocus(GetDlgItem(hwnd,START_BUTTON));
KillTimer(hwnd, TIMER_ID2); KillFileCreate = FALSE;
sprintf(buffer,"STOPPED"); Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
DestroyWindow(Gauge); UpdateWindow(hwnd);
break; }
KillTimer(hwnd, TIMER_ID);
//
// If the thread is not running disregard it.
//
GetExitCodeThread(ThrdHandle,&exitCode); if (exitCode == STILL_ACTIVE) {
//
// Set flag to kill the threads.
//
RunTest = FALSE;
if ((WaitForSingleObject (ThrdHandle,INFINITE)) == WAIT_FAILED) {
//
// TODO: Do something drastic.
//
} }
//
// Re-enable/disable buttons
//
Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE); Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE);
SetFocus(GetDlgItem(hwnd,START_BUTTON));
sprintf(buffer,"STOPPED"); Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer);
break;
case QUIT_BUTTON: case IDCANCEL: EndDialog(hwnd, id); break; default: break; } }
VOID ProcessSpinCmds( HWND hwnd, HWND hCtl, UINT code, INT position) { CHAR buffer[34];
if (hCtl == GetDlgItem(hwnd,SPIN_CTL)) {
//
// Get the current buffer size
//
Static_GetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer,sizeof(buffer)); BufferSize = atol(buffer); switch (code) { case SB_PAGEDOWN: case SB_BOTTOM: case SB_LINEDOWN: if ((BufferSize -= SectorSize) < SectorSize) { BufferSize = 1048576; }
NumberIOs = FILE_SIZE / BufferSize; _ultoa(BufferSize,buffer,10); Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer); break;
case SB_LINEUP: case SB_PAGEUP: case SB_TOP:
if ((BufferSize += SectorSize) > 1048576) { BufferSize = SectorSize; }
NumberIOs = FILE_SIZE / BufferSize; _ultoa(BufferSize,buffer,10); Static_SetText(GetDlgItem(hwnd,BUFFER_TEXT),buffer); break;
case SB_THUMBPOSITION: case SB_THUMBTRACK: break; } } }
VOID FormatTime(ULONG Time) {
++Seconds; if (Seconds % 60 == 0) { ++Minutes; Seconds = 0;
if(Minutes % 60 == 0) { ++Hours; Minutes = 0;
if(Hours % 24 == 0) { ++Days; Hours = 0; } } }
sprintf(TimerText,"%02d:%02d:%02d:%02d",Days,Hours,Minutes,Seconds); }
VOID ProcessTimer( HWND hwnd, UINT id) {
CHAR buffer[40];
if (id == TIMER_ID) {
++ElapsedTime; FormatTime (ElapsedTime); SetWindowText(GetDlgItem(hwnd,TIME_TEXT),TimerText);
} else if (id == TIMER_ID2) {
//
// Get status of file create thread.
//
if ( WaitForSingleObject (ThrdHandle,0) == WAIT_OBJECT_0) {
TestFileCreated = TRUE; KillTimer(hwnd, TIMER_ID2);
DestroyWindow(Gauge); UpdateWindow(hwnd);
//
// Redo controls
//
Button_Enable(GetDlgItem(hwnd,START_BUTTON), TRUE); Button_Enable(GetDlgItem(hwnd,STOP_BUTTON), FALSE); SetFocus(GetDlgItem(hwnd,START_BUTTON));
sprintf(buffer,"READY"); Static_SetText(GetDlgItem(hwnd,STATUS_TEST), buffer); } }
}
INT_PTR CALLBACK BenchDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { BOOL Processed = TRUE;
switch (uMsg) { HANDLE_MSG(hDlg, WM_INITDIALOG, InitDialog); HANDLE_MSG(hDlg, WM_COMMAND, ProcessCommands); HANDLE_MSG(hDlg, WM_VSCROLL, ProcessSpinCmds); HANDLE_MSG(hDlg, WM_TIMER, ProcessTimer);
default: Processed = FALSE; break; } return Processed; }
INT APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR CmdLine, INT CmdShow) { CHAR buffer[10]; PCHAR tmp = buffer, cmdLinePtr, ptr; //
// Check for, and process cmd line.
//
HInst = hInstance;
cmdLinePtr = CmdLine; if (*cmdLinePtr != '\0') {
while (*cmdLinePtr != '\0') { tmp = buffer; memset (tmp,0,sizeof(buffer)); if (*cmdLinePtr == '-') { switch (*(cmdLinePtr + 1)) { case 'b': case 'B': ptr = cmdLinePtr + 2; while (*ptr != ' ') { *tmp++ = *ptr++; } BufferSize = 1024 * atol(buffer); cmdLinePtr = ptr; while (*cmdLinePtr++ == ' '); --cmdLinePtr; break; case 't': case 'T': ptr = cmdLinePtr + 2; if (*ptr != 'r' && *ptr != 'R' && *ptr != 'w' && *ptr != 'W') { Usage(); return 1; } index = (*ptr == 'R' || *ptr == 'r') ? 0 : 1; ++ptr;
if (*ptr != 's' && *ptr != 'S' && *ptr != 'r' && *ptr != 'R') { Usage(); return 1; } index <<= 1; index |= (*ptr == 'S' || *ptr == 's') ? 0 : 1; ++ptr; cmdLinePtr = ptr; while (*cmdLinePtr++ == ' '); --cmdLinePtr; break;
default: Usage(); return 1; } } else if (*(cmdLinePtr + 1) == ':') { sprintf (buffer,"%c%c%c",toupper(*cmdLinePtr),':','\\'); strcat (TestDrv,buffer);
while (*cmdLinePtr++ != ' '); while (*cmdLinePtr++ == ' ');
--cmdLinePtr;
} else { Usage(); return 1; } }
}
DialogBox(hInstance, MAKEINTRESOURCE(BENCH_DLG), NULL, BenchDlgProc); return(0); }
DWORD ReadSequential( PPARAMS Params ) { ULONG j, errCode, outstandingRequests; HANDLE file, port; OVERLAPPED overlapped, *overlapped2; DWORD bytesRead, bytesRead2, version; DWORD_PTR completionKey; BOOL status; PUCHAR buffer;
version = GetVersion() >> 16;
buffer = VirtualAlloc(NULL, Params->BufferSize + SectorSize - 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
(ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
if ( !buffer ) { LogError("Error allocating buffer",1,GetLastError()); ExitThread(1); return 2; }
while (RunTest) {
file = CreateFile(Params->TargetFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL );
if ( file == INVALID_HANDLE_VALUE ) { LogError("Error opening Target file",2,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(2); return 2; }
port = CreateIoCompletionPort(file, NULL, (DWORD_PTR)file, 0); if ( !port ) { LogError("Error creating completion port",3,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(3); return 3; }
memset(&overlapped,0,sizeof(overlapped));
outstandingRequests = 0;
for (j = 0; j < Params->Tcount; j++) { do {
status = ReadFile(file, buffer, Params->BufferSize, &bytesRead, &overlapped);
errCode = GetLastError();
if (!status) { if (errCode == ERROR_IO_PENDING) { break; } else if (errCode == ERROR_NOT_ENOUGH_QUOTA || errCode == ERROR_INVALID_USER_BUFFER || errCode == ERROR_NOT_ENOUGH_MEMORY) { //
// Allow this to retry.
//
} else { LogError("Error in ReadFile",4,errCode); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(4); return 4; }
}
} while (!status);
outstandingRequests++; overlapped.Offset += Params->BufferSize; }
for (j = 0; j < outstandingRequests; j++) {
status = GetQueuedCompletionStatus(port, &bytesRead2, &completionKey, &overlapped2, (DWORD)-1);
if (!status) { LogError("GetQueuedCompletionStatus error.",5,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(5); return 5; }
}
if (version > 612) { CloseHandle(port); }
CloseHandle(file);
}
VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT);
ExitThread(0); return 0; }
DWORD WriteSequential( PPARAMS Params ) {
ULONG j, errCode, outstandingRequests; HANDLE file, port; OVERLAPPED overlapped, *overlapped2; DWORD bytesWrite, bytesWrite2, version; DWORD_PTR completionKey; BOOL status; PUCHAR buffer;
version = GetVersion() >> 16;
buffer = VirtualAlloc(NULL, Params->BufferSize + SectorSize - 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
(ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
if ( !buffer ) { LogError("Error allocating buffer",1,GetLastError()); ExitThread(1); return 2; }
while (RunTest) {
file = CreateFile(Params->TargetFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL );
if ( file == INVALID_HANDLE_VALUE ) { LogError("Error opening Target file",2,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(2); return 2; }
port = CreateIoCompletionPort(file, NULL, (DWORD_PTR)file, 0); if ( !port ) { LogError("Error creating completion port",3,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(3); return 3; }
memset(&overlapped,0,sizeof(overlapped));
outstandingRequests = 0;
for (j = 0; j < Params->Tcount; j++) { do {
status = WriteFile(file, buffer, Params->BufferSize, &bytesWrite, &overlapped);
errCode = GetLastError();
if (!status) { if (errCode == ERROR_IO_PENDING) { break; } else if (errCode == ERROR_NOT_ENOUGH_QUOTA || errCode == ERROR_INVALID_USER_BUFFER || errCode == ERROR_NOT_ENOUGH_MEMORY) { //
// Allow this to retry.
//
} else { LogError("Error in WriteFile",4,errCode); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(4); return 4; }
}
} while (!status);
outstandingRequests++; overlapped.Offset += Params->BufferSize; }
for (j = 0; j < outstandingRequests; j++) {
status = GetQueuedCompletionStatus(port, &bytesWrite2, &completionKey, &overlapped2, (DWORD)-1);
if (!status) { LogError("GetQueuedCompletionStatus error.",5,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(5); return 5; }
}
if (version > 612) { CloseHandle(port); }
CloseHandle(file);
}
VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT);
ExitThread(0); return 0; }
DWORD ReadRandom( PPARAMS Params ) {
ULONG j, errCode, outstandingRequests; HANDLE file, port; OVERLAPPED overlapped, *overlapped2; DWORD bytesRead, bytesRead2, version; DWORD_PTR completionKey; BOOL status; PUCHAR buffer;
version = GetVersion() >> 16;
buffer = VirtualAlloc(NULL, Params->BufferSize + SectorSize - 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
(ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
if ( !buffer ) { LogError("Error allocating buffer",1,GetLastError()); ExitThread(1); return 2; }
while (RunTest) {
file = CreateFile(Params->TargetFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL );
if ( file == INVALID_HANDLE_VALUE ) { LogError("Error opening Target file",2,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(2); return 2; }
port = CreateIoCompletionPort(file, NULL, (DWORD_PTR)file, 0); if ( !port ) { LogError("Error creating completion port",3,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(3); return 3; }
memset(&overlapped,0,sizeof(overlapped));
outstandingRequests = 0;
for (j = 0; j < Params->Tcount; j++) { do {
status = ReadFile(file, buffer, Params->BufferSize, &bytesRead, &overlapped);
errCode = GetLastError();
if (!status) { if (errCode == ERROR_IO_PENDING) { break; } else if (errCode == ERROR_NOT_ENOUGH_QUOTA || errCode == ERROR_INVALID_USER_BUFFER || errCode == ERROR_NOT_ENOUGH_MEMORY) { //
// Allow this to retry.
//
} else { LogError("Error in ReadFile",4,errCode); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(4); return 4; }
}
} while (!status);
outstandingRequests++; overlapped.Offset = GetRandomOffset(0,FILE_SIZE - Params->BufferSize); }
for (j = 0; j < outstandingRequests; j++) {
status = GetQueuedCompletionStatus(port, &bytesRead2, &completionKey, &overlapped2, (DWORD)-1);
if (!status) { LogError("GetQueuedCompletionStatus error.",5,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(5); return 5; }
}
if (version > 612) { CloseHandle(port); }
CloseHandle(file);
}
VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT);
ExitThread(0); return 0; }
DWORD WriteRandom( PPARAMS Params ) { ULONG j, errCode, outstandingRequests; HANDLE file, port; OVERLAPPED overlapped, *overlapped2; DWORD bytesWrite, bytesWrite2, version; DWORD_PTR completionKey; BOOL status; PUCHAR buffer;
version = GetVersion() >> 16;
buffer = VirtualAlloc(NULL, Params->BufferSize + SectorSize - 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
(ULONG_PTR)buffer &= ~((ULONG_PTR)SectorSize - 1);
if ( !buffer ) { LogError("Error allocating buffer",1,GetLastError()); ExitThread(1); return 2; }
while (RunTest) {
file = CreateFile(Params->TargetFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL );
if ( file == INVALID_HANDLE_VALUE ) { LogError("Error opening Target file",2,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(2); return 2; }
port = CreateIoCompletionPort(file, NULL, (DWORD_PTR)file, 0); if ( !port ) { LogError("Error creating completion port",3,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(3); return 3; }
memset(&overlapped,0,sizeof(overlapped));
outstandingRequests = 0;
for (j = 0; j < Params->Tcount; j++) { do {
status = WriteFile(file, buffer, Params->BufferSize, &bytesWrite, &overlapped);
errCode = GetLastError();
if (!status) { if (errCode == ERROR_IO_PENDING) { break; } else if (errCode == ERROR_NOT_ENOUGH_QUOTA || errCode == ERROR_INVALID_USER_BUFFER || errCode == ERROR_NOT_ENOUGH_MEMORY) { //
// Allow this to retry.
//
} else { LogError("Error in WriteFile",4,errCode); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(4); return 4; }
}
} while (!status);
outstandingRequests++; overlapped.Offset = GetRandomOffset(0,FILE_SIZE - Params->BufferSize); }
for (j = 0; j < outstandingRequests; j++) {
status = GetQueuedCompletionStatus(port, &bytesWrite2, &completionKey, &overlapped2, (DWORD)-1);
if (!status) { LogError("GetQueuedCompletionStatus error.",5,GetLastError()); VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT); ExitThread(5); return 5; }
}
if (version > 612) { CloseHandle(port); }
CloseHandle(file);
}
VirtualFree(buffer, Params->BufferSize + SectorSize - 1, MEM_DECOMMIT);
ExitThread(0); return 0; }
ULONG GetRandomOffset( ULONG min, ULONG max ) {
INT base = rand(); ULONG retval = ((max - min) / RAND_MAX) * base; retval += SectorSize -1; retval &= ~(SectorSize - 1); if (retval < min) { return min; } else if (retval > max ){ return max & ~(SectorSize - 1); } else{ return retval; }
}
VOID LogError( PCHAR ErrString, DWORD UniqueId, DWORD ErrCode ) { CHAR ErrBuf[80]; #if DBG
sprintf(ErrBuf,"%d: %s WinError %d",UniqueId,ErrString,ErrCode); MessageBox(NULL,ErrBuf,"Error",MB_OK | MB_ICONEXCLAMATION); #else
return; #endif
}
BOOL GetSectorSize( PDWORD SectorSize, PCHAR DrvLetter ) { DISK_GEOMETRY DiskGeometry; DWORD BytesReturned; HANDLE handle;
handle = CreateFile(DrvLetter, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL ); if (handle == INVALID_HANDLE_VALUE) { return FALSE; }
//
// Starting offset and sectors
//
if (!DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), &BytesReturned, NULL )) { return FALSE; } *SectorSize = DiskGeometry.BytesPerSector;
return TRUE; }
VOID Usage( VOID ) { CHAR buffer[255];
sprintf(buffer,"\nDSKBENCH: V1.0\n\n"); strcat (buffer,"Usage: DSKBENCH\n"); strcat (buffer,"\t[Drvletter:]\n\t[-b] Buffer size in 1kb increments.\n\t[-tXX] Test specifier."); strcat (buffer,"\n\tWhere XX is:\n\t\t'RS' - Read sequential.\n\t\t'RR' - Read Random\n\t\t"); strcat (buffer,"'WS' - Write sequential\n\t\t'WR' - Write Random\n\n"); strcat (buffer,"Example: Dskbench d: -b64 -tRS\n");
MessageBox(NULL,buffer,"Usage",MB_OK); }
|