singrdk/base/Windows/Benchmarks/diskrw/diskrw.cpp

445 lines
14 KiB
C++
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
////////////////////////////////////////////////////////////////////////////
//
// Boot Service
//
// Copyright Microsoft Corporation
//
#define UNICODE
#define _UNICODE
#define _WIN32_WINNT 0x500
#include <winlean.h>
#include <winioctl.h>
#include "wincrypt.h"
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "srandom.hpp"
#define ARRAYOF(x) (sizeof(x)/sizeof(x[0]))
#define ASSERT(a) assert(a)
//////////////////////////////////////////////////////////////////////////////
//
static SRandom g_Rng;
static DWORD64 g_MaxBlock;
static DWORD g_BlockBytes;
static void ResetOffsetRNG(DWORD64 diskBytes, DWORD blockBytes)
{
g_Rng.reset();
assert(blockBytes != 0);
g_MaxBlock = diskBytes / blockBytes;
g_BlockBytes = blockBytes;
}
static DWORD64 GetRandomOffset()
{
static_assert(SRandom::Maximum == 0x7fffffff);
DWORD64 offset = 0;
for (int i = 0; i < 64; i += 30) {
offset ^= (DWORD64)(g_Rng.next() << i);
}
offset &= 0x7fffffffffffffffi64;
offset %= g_MaxBlock;
assert (offset >= 0 && offset < g_MaxBlock);
return offset * g_BlockBytes;
}
//////////////////////////////////////////////////////////////////////////////
//
DWORD64 GetDiskSize(HANDLE hDisk)
{
DWORD junk; // discard results
DISK_GEOMETRY dg;
ZeroMemory(&dg, sizeof(dg));
if (!DeviceIoControl(hDisk, // device to be queried
IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform
NULL, 0, // no input buffer
&dg, sizeof(dg), // output buffer
&junk, // # bytes returned
NULL)) {
printf("DeviceIoControl failed: %d\n", GetLastError());
return 0;
}
return dg.Cylinders.QuadPart * (ULONG)dg.TracksPerCylinder *
(ULONG)dg.SectorsPerTrack * (ULONG)dg.BytesPerSector;
}
DWORD64 GetPartitionSize(HANDLE hDisk)
{
DWORD junk; // discard results
PARTITION_INFORMATION_EX pi;
ZeroMemory(&pi, sizeof(pi));
if (!DeviceIoControl(hDisk, // device to be queried
IOCTL_DISK_GET_PARTITION_INFO_EX, // operation to perform
NULL, 0, // no input buffer
&pi, sizeof(pi), // output buffer
&junk, // # bytes returned
NULL)) {
printf("DeviceIoControl failed: %d\n", GetLastError());
return 0;
}
return pi.PartitionLength.QuadPart;
}
int DiskReadTest(PCWSTR pwzDisk,
DWORD dwBlockSize,
DWORD dwBlockCount,
DWORD dwLimit,
BOOL fRandom,
BOOL fWriteThrough)
{
PBYTE pbBuffer = (PBYTE)VirtualAlloc(NULL, 0x100000, MEM_COMMIT, PAGE_READWRITE);
if (pbBuffer == NULL) {
printf("VirtualAlloc failed: %d\n", GetLastError());
return 1;
}
DWORD dwAttributes = FILE_FLAG_NO_BUFFERING;
if (fWriteThrough)
{
dwAttributes |= FILE_FLAG_WRITE_THROUGH;
}
HANDLE hDisk = CreateFile(pwzDisk, // drive to open
GENERIC_READ, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
dwAttributes,
NULL); // do not copy file attributes
if (hDisk == INVALID_HANDLE_VALUE) // cannot open the drive
{
printf("CreateFile failed: %d\n", GetLastError());
return 1;
}
DWORD64 dwDisk = GetPartitionSize(hDisk);
// DWORD64 dwDisk = GetDiskSize(hDisk);
if (dwLimit != 0) {
dwDisk = dwLimit * 1024i64 * 1024i64;
}
DWORD64 dwTotal = dwBlockCount * dwBlockSize;
printf("# Type: %s Read\n", fRandom ? "Random" : "Sequential");
printf("# Disk: %10I64d MB\n", dwDisk / (1024 * 1024));
printf("# Limit: %10d MB\n", dwLimit);
printf("# Work: %10.2f MB\n", (float)dwTotal / (1024 * 1024));
printf("# Ops: %10d\n", dwTotal / dwBlockSize);
DWORD dwOps = 0;
LARGE_INTEGER before;
QueryPerformanceCounter(&before);
LARGE_INTEGER liPos;
if (fRandom) {
ResetOffsetRNG(dwDisk, dwBlockSize);
liPos.QuadPart = GetRandomOffset();
while (dwOps++ < dwBlockCount) {
if (SetFilePointerEx(hDisk, liPos, NULL, FILE_BEGIN) == FALSE) {
printf("SetFilePointerEx failed: %d\n", GetLastError());
return 1;
}
liPos.QuadPart = GetRandomOffset();
DWORD cbRead = 0;
if (!ReadFile(hDisk, pbBuffer, dwBlockSize, &cbRead, NULL)) {
printf("ReadFile failed: %d\n", GetLastError());
return 1;
}
}
}
else {
liPos.QuadPart = 0;
while (dwOps++ < dwBlockCount) {
if (SetFilePointerEx(hDisk, liPos, NULL, FILE_BEGIN) == FALSE) {
printf("SetFilePointerEx failed: %d\n", GetLastError());
return 1;
}
liPos.QuadPart += dwBlockSize;
DWORD cbRead;
if (!ReadFile(hDisk, pbBuffer, dwBlockSize, &cbRead, NULL)) {
printf("ReadFile failed: %d\n", GetLastError());
return 1;
}
}
}
LARGE_INTEGER after;
QueryPerformanceCounter(&after);
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
CloseHandle(hDisk);
after.QuadPart -= before.QuadPart;
//printf("Delta : %18I64d\n", after.QuadPart);
//printf("Freque: %18I64d\n", frequency.QuadPart);
double elapsed = (double)after.QuadPart / (double)frequency.QuadPart;
printf("%cR.%d ", fRandom ? 'R' : 'S', dwBlockSize);
printf("Mbps %10.3f Ops/Sec: %10.3f Elapsed %10.3f Check 0x%I64x\n",
((double)dwTotal) / (1024 * 1024 * elapsed),
(double)dwOps / elapsed,
elapsed, liPos.QuadPart);
return 0;
}
int DiskWriteTest(PCWSTR pwzDisk,
DWORD dwBlockSize,
DWORD dwBlockCount,
DWORD dwLimit,
BOOL fRandom,
BOOL fWriteThrough)
{
PBYTE pbBuffer = (PBYTE)VirtualAlloc(NULL, 0x100000, MEM_COMMIT, PAGE_READWRITE);
if (pbBuffer == NULL) {
printf("VirtualAlloc failed: %d\n", GetLastError());
return 1;
}
DWORD dwAttributes = FILE_FLAG_NO_BUFFERING;
if (fWriteThrough)
{
dwAttributes |= FILE_FLAG_WRITE_THROUGH;
}
HANDLE hDisk = CreateFile(pwzDisk, // drive to open
GENERIC_WRITE | GENERIC_READ,
0,
NULL, // default security attributes
OPEN_EXISTING, // disposition
dwAttributes,
NULL); // do not copy file attributes
if (hDisk == INVALID_HANDLE_VALUE) // cannot open the drive
{
printf("CreateFile failed: %d\n", GetLastError());
return 1;
}
DWORD64 dwDisk = GetPartitionSize(hDisk);
if (dwLimit != 0) {
dwDisk = dwLimit * 1024i64 * 1024i64;
}
DWORD64 dwTotal = dwBlockCount * dwBlockSize;
printf("# Type: %s Write\n", fRandom ? "Random" : "Sequential");
printf("# Disk: %10I64d MB\n", dwDisk / (1024 * 1024));
printf("# Work: %10.2f MB\n", (float)dwTotal / (1024 * 1024));
printf("# Ops: %10d\n", dwTotal / dwBlockSize);
DWORD dwOps = 0;
LARGE_INTEGER before;
QueryPerformanceCounter(&before);
LARGE_INTEGER liPos;
if (fRandom) {
ResetOffsetRNG(dwDisk, dwBlockSize);
liPos.QuadPart = GetRandomOffset();
while (dwOps++ < dwBlockCount) {
if (SetFilePointerEx(hDisk, liPos, NULL, FILE_BEGIN) == FALSE) {
printf("SetFilePointerEx failed: %d\n", GetLastError());
return 1;
}
liPos.QuadPart = GetRandomOffset();
DWORD cbRead = 0;
if (!WriteFile(hDisk, pbBuffer, dwBlockSize, &cbRead, NULL)) {
printf("WriteFile failed: %d\n", GetLastError());
return 1;
}
}
}
else {
liPos.QuadPart = 0;
while (dwOps++ < dwBlockCount) {
if (SetFilePointerEx(hDisk, liPos, NULL, FILE_BEGIN) == FALSE) {
printf("SetFilePointerEx failed: %d\n", GetLastError());
return 1;
}
liPos.QuadPart += dwBlockSize;
DWORD cbRead;
if (!WriteFile(hDisk, pbBuffer, dwBlockSize, &cbRead, NULL)) {
printf("WriteFile failed: %d\n", GetLastError());
return 1;
}
}
}
LARGE_INTEGER after;
QueryPerformanceCounter(&after);
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
CloseHandle(hDisk);
after.QuadPart -= before.QuadPart;
//printf("Delta : %18I64d\n", after.QuadPart);
//printf("Freque: %18I64d\n", frequency.QuadPart);
double elapsed = (double)after.QuadPart / (double)frequency.QuadPart;
printf("%cW.%d ", fRandom ? 'R' : 'S', dwBlockSize);
printf("Mbps: %10.3f Ops/Sec: %10.3f Elapsed: %10.3f Check: 0x%I64x\n",
((double)dwTotal) / (1024 * 1024 * elapsed),
(double)dwOps / elapsed, elapsed, liPos.QuadPart);
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//
int __cdecl wmain(int argc, WCHAR **argv)
{
BOOL fNeedHelp = FALSE;
BOOL fRead = FALSE;
BOOL fWrite = FALSE;
DWORD dwBlock = 512;
DWORD dwMegabytes = 0;
DWORD dwBlockCount = 0;
BOOL fRandom = FALSE;
BOOL fWriteThrough = TRUE;
DWORD dwLimit = 0;
WCHAR wzPartition[64] = L"";
for (int arg = 1; arg < argc && !fNeedHelp; arg++) {
if (argv[arg][0] == '-' || argv[arg][0] == '/') {
WCHAR *argn = argv[arg]+1; // Argument name
WCHAR *argp = argn; // Argument parameter
while (*argp && *argp != ':') {
argp++;
}
if (*argp == ':')
*argp++ = '\0';
switch (argn[0]) {
case '?': // Help
fNeedHelp = TRUE;
break;
case 'b': // Block size
case 'B':
dwBlock = (DWORD)_wtoi(argp);
break;
case 'l': // Disk Limit Megabytes
case 'L':
dwLimit = (DWORD)_wtoi(argp);
break;
case 'm': // Megabytes of Data
case 'M':
dwMegabytes = (DWORD)_wtoi(argp);
break;
case 'n': // Number of blocks
case 'N':
dwBlockCount = (DWORD)_wtoi(argp);
break;
case 'r': // Read
case 'R':
fRead = TRUE;
break;
case 'w': // Write
case 'W':
fWrite = TRUE;
break;
case 'x': // Xtremely Random
case 'X':
fRandom = TRUE;
break;
case 'z':
case 'Z':
fWriteThrough = FALSE;
break;
default:
printf("Unknown argument: %ls\n", argv[arg]);
fNeedHelp = TRUE;
break;
}
}
else {
wsprintf(wzPartition, L"\\\\.\\%ls", argv[arg]);
}
}
if (dwBlock < 512 || dwBlock & (dwBlock - 1)) {
fprintf(stderr, "Block size needs to be a power of 2 greater than or equal to 512.\n");
fNeedHelp = true;
}
if ((dwBlockCount == 0 && dwMegabytes == 0) ||
(dwBlockCount != 0 && dwMegabytes != 0)) {
fprintf(stderr, "Need to specify either number of blocks or number of megabytes for I/O.\n");
fNeedHelp = true;
}
if (dwMegabytes > 0) {
DWORD64 tmp = (dwMegabytes * 1048576i64) / dwBlock;
dwBlockCount = (DWORD) tmp;
}
if (argc == 1) {
fNeedHelp = TRUE;
}
if (fNeedHelp) {
printf(
"Usage:\n"
" diskrw [options] {drive letter:}\n"
"Options:\n"
" /b:N -- Block size (in bytes).\n"
" /l:M -- Limit (defaults to full partition) in megabytes.\n"
" /m:M -- Megabytes to read or write.\n"
" /n:N -- Number of blocks to read or write.\n"
" /x -- Random, otherwise, defaults to sequential.\n"
" /z -- No write through, defaults to write through.\n"
" /r -- Read.\n"
" /w -- Write.\n"
" /? -- Display this help screen.\n"
"Example:\n"
" diskrw /r /x /b:512 c:\n"
);
return 1;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
printf("# Disk: %ls\n", wzPartition);
if (fRead) {
DiskReadTest(wzPartition, dwBlock, dwBlockCount, dwLimit, fRandom, fWriteThrough);
}
else if (fWrite){
DiskWriteTest(wzPartition, dwBlock, dwBlockCount, dwLimit, fRandom, fWriteThrough);
}
return 0;
}
//
///////////////////////////////////////////////////////////////// End of File.