1654 lines
43 KiB
C
1654 lines
43 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|