windows-nt/Source/XPSP1/NT/sdktools/dskbench/dskbench.c

1654 lines
43 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}