Добавлена папка source в CristalDiskMark
This commit is contained in:
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
|
||||
DISKSPD
|
||||
|
||||
Copyright(c) Microsoft Corporation
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#include <Winternl.h> //ntdll.dll
|
||||
#include <assert.h>
|
||||
#include "Histogram.h"
|
||||
#include "IoBucketizer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// structures used for passing the input parameters
|
||||
|
||||
// versioning material. for simplicity in consumption, please ensure that the date string
|
||||
// parses via the System.Datetime constructor as follows (in Powershell):
|
||||
//
|
||||
// [datetime] "string"
|
||||
//
|
||||
// this should result in a valid System.Datetime object, rendered like:
|
||||
//
|
||||
// Monday, June 16, 2014 12:00:00 AM
|
||||
|
||||
#define DISKSPD_RELEASE_TAG ""
|
||||
#define DISKSPD_NUMERIC_VERSION_STRING "2.0.15" DISKSPD_RELEASE_TAG
|
||||
#define DISKSPD_DATE_VERSION_STRING "2015/01/09"
|
||||
|
||||
typedef void (WINAPI *PRINTF)(const char*, va_list); //function used for displaying formatted data (printf style)
|
||||
|
||||
struct ETWEventCounters
|
||||
{
|
||||
UINT64 ullIORead; // Read
|
||||
UINT64 ullIOWrite; // Write
|
||||
UINT64 ullMMTransitionFault; // Transition fault
|
||||
UINT64 ullMMDemandZeroFault; // Demand Zero fault
|
||||
UINT64 ullMMCopyOnWrite; // Copy on Write
|
||||
UINT64 ullMMGuardPageFault; // Guard Page fault
|
||||
UINT64 ullMMHardPageFault; // Hard page fault
|
||||
UINT64 ullNetTcpSend; // Send
|
||||
UINT64 ullNetTcpReceive; // Receive
|
||||
UINT64 ullNetUdpSend; // Send
|
||||
UINT64 ullNetUdpReceive; // Receive
|
||||
UINT64 ullNetConnect; // Connect
|
||||
UINT64 ullNetDisconnect; // Disconnect
|
||||
UINT64 ullNetRetransmit; // ReTransmit
|
||||
UINT64 ullNetAccept; // Accept
|
||||
UINT64 ullNetReconnect; // ReConnect
|
||||
UINT64 ullRegCreate; // NtCreateKey
|
||||
UINT64 ullRegOpen; // NtOpenKey
|
||||
UINT64 ullRegDelete; // NtDeleteKey
|
||||
UINT64 ullRegQuery; // NtQueryKey
|
||||
UINT64 ullRegSetValue; // NtSetValueKey
|
||||
UINT64 ullRegDeleteValue; // NtDeleteValueKey
|
||||
UINT64 ullRegQueryValue; // NtQueryValueKey
|
||||
UINT64 ullRegEnumerateKey; // NtEnumerateKey
|
||||
UINT64 ullRegEnumerateValueKey; // NtEnumerateValueKey
|
||||
UINT64 ullRegQueryMultipleValue; // NtQueryMultipleValueKey
|
||||
UINT64 ullRegSetInformation; // NtSetInformationKey
|
||||
UINT64 ullRegFlush; // NtFlushKey
|
||||
UINT64 ullRegKcbDmp; // KcbDump/create
|
||||
UINT64 ullThreadStart;
|
||||
UINT64 ullThreadEnd;
|
||||
UINT64 ullProcessStart;
|
||||
UINT64 ullProcessEnd;
|
||||
UINT64 ullImageLoad;
|
||||
};
|
||||
|
||||
|
||||
// structure containing informations about ETW session
|
||||
struct ETWSessionInfo
|
||||
{
|
||||
ULONG ulBufferSize;
|
||||
ULONG ulMinimumBuffers;
|
||||
ULONG ulMaximumBuffers;
|
||||
ULONG ulFreeBuffers;
|
||||
ULONG ulBuffersWritten;
|
||||
ULONG ulFlushTimer;
|
||||
LONG lAgeLimit;
|
||||
ULONG ulNumberOfBuffers;
|
||||
ULONG ulEventsLost;
|
||||
ULONG ulLogBuffersLost;
|
||||
ULONG ulRealTimeBuffersLost;
|
||||
};
|
||||
|
||||
// structure containing parameters concerning ETW session provided by user
|
||||
struct ETWMask
|
||||
{
|
||||
BOOL bProcess;
|
||||
BOOL bThread;
|
||||
BOOL bImageLoad;
|
||||
BOOL bDiskIO;
|
||||
BOOL bMemoryPageFaults;
|
||||
BOOL bMemoryHardFaults;
|
||||
BOOL bNetwork;
|
||||
BOOL bRegistry;
|
||||
BOOL bUsePagedMemory;
|
||||
BOOL bUsePerfTimer;
|
||||
BOOL bUseSystemTimer;
|
||||
BOOL bUseCyclesCounter;
|
||||
};
|
||||
|
||||
namespace UnitTests
|
||||
{
|
||||
class PerfTimerUnitTests;
|
||||
class ProfileUnitTests;
|
||||
class TargetUnitTests;
|
||||
}
|
||||
|
||||
class PerfTimer
|
||||
{
|
||||
public:
|
||||
|
||||
static UINT64 GetTime();
|
||||
|
||||
static double PerfTimeToMicroseconds(const double);
|
||||
static double PerfTimeToMilliseconds(const double);
|
||||
static double PerfTimeToSeconds(const double);
|
||||
static double PerfTimeToMicroseconds(const UINT64);
|
||||
static double PerfTimeToMilliseconds(const UINT64);
|
||||
static double PerfTimeToSeconds(const UINT64);
|
||||
|
||||
static UINT64 MicrosecondsToPerfTime(const double);
|
||||
static UINT64 MillisecondsToPerfTime(const double);
|
||||
static UINT64 SecondsToPerfTime(const double);
|
||||
|
||||
private:
|
||||
|
||||
static const UINT64 TIMER_FREQ;
|
||||
static UINT64 _GetPerfTimerFreq();
|
||||
|
||||
friend class UnitTests::PerfTimerUnitTests;
|
||||
};
|
||||
|
||||
struct PercentileDescriptor
|
||||
{
|
||||
double Percentile;
|
||||
string Name;
|
||||
};
|
||||
|
||||
class Util
|
||||
{
|
||||
public:
|
||||
static string DoubleToStringHelper(const double);
|
||||
template<typename T> static T QuotientCeiling(T dividend, T divisor)
|
||||
{
|
||||
return (dividend + divisor - 1) / divisor;
|
||||
}
|
||||
};
|
||||
|
||||
// To keep track of which type of IO was issued
|
||||
enum class IOOperation
|
||||
{
|
||||
ReadIO = 1,
|
||||
WriteIO
|
||||
};
|
||||
|
||||
class TargetResults
|
||||
{
|
||||
public:
|
||||
TargetResults() :
|
||||
ullFileSize(0),
|
||||
ullBytesCount(0),
|
||||
ullIOCount(0),
|
||||
ullReadBytesCount(0),
|
||||
ullReadIOCount(0),
|
||||
ullWriteBytesCount(0),
|
||||
ullWriteIOCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Add(DWORD dwBytesTransferred,
|
||||
IOOperation type,
|
||||
PUINT64 pullIoStartTime,
|
||||
PUINT64 pullSpanStartTime,
|
||||
bool fMeasureLatency,
|
||||
bool fCalculateIopsStdDev
|
||||
)
|
||||
{
|
||||
float fDurationMsec = 0;
|
||||
UINT64 ullEndTime = 0;
|
||||
// assume it is worthwhile to stay off of the time query path unless needed (micro-overhead)
|
||||
if (fMeasureLatency || fCalculateIopsStdDev)
|
||||
{
|
||||
ullEndTime = PerfTimer::GetTime();
|
||||
}
|
||||
|
||||
if (fMeasureLatency)
|
||||
{
|
||||
UINT64 ullDuration = ullEndTime - *pullIoStartTime;
|
||||
fDurationMsec = static_cast<float>(PerfTimer::PerfTimeToMicroseconds(ullDuration));
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readLatencyHistogram.Add(fDurationMsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeLatencyHistogram.Add(fDurationMsec);
|
||||
}
|
||||
}
|
||||
|
||||
UINT64 ullRelativeCompletionTime = 0;
|
||||
if (fCalculateIopsStdDev)
|
||||
{
|
||||
ullRelativeCompletionTime = ullEndTime - *pullSpanStartTime;
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readBucketizer.Add(ullRelativeCompletionTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBucketizer.Add(ullRelativeCompletionTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
ullReadBytesCount += dwBytesTransferred; // update read bytes counter
|
||||
ullReadIOCount++; // update completed read I/O operations counter
|
||||
}
|
||||
else
|
||||
{
|
||||
ullWriteBytesCount += dwBytesTransferred; // update write bytes counter
|
||||
ullWriteIOCount++; // update completed write I/O operations counter
|
||||
}
|
||||
|
||||
ullBytesCount += dwBytesTransferred; // update bytes counter
|
||||
ullIOCount++; // update completed I/O operations counter
|
||||
}
|
||||
|
||||
string sPath;
|
||||
UINT64 ullFileSize; //size of the file
|
||||
UINT64 ullBytesCount; //number of accessed bytes
|
||||
UINT64 ullIOCount; //number of performed I/O operations
|
||||
UINT64 ullReadBytesCount; //number of bytes read
|
||||
UINT64 ullReadIOCount; //number of performed Read I/O operations
|
||||
UINT64 ullWriteBytesCount; //number of bytes written
|
||||
UINT64 ullWriteIOCount; //number of performed Write I/O operations
|
||||
|
||||
Histogram<float> readLatencyHistogram;
|
||||
Histogram<float> writeLatencyHistogram;
|
||||
|
||||
IoBucketizer readBucketizer;
|
||||
IoBucketizer writeBucketizer;
|
||||
};
|
||||
|
||||
class ThreadResults
|
||||
{
|
||||
public:
|
||||
vector<TargetResults> vTargetResults;
|
||||
};
|
||||
|
||||
class Results
|
||||
{
|
||||
public:
|
||||
bool fUseETW;
|
||||
struct ETWEventCounters EtwEventCounters;
|
||||
struct ETWMask EtwMask;
|
||||
struct ETWSessionInfo EtwSessionInfo;
|
||||
vector<ThreadResults> vThreadResults;
|
||||
UINT64 ullTimeCount;
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vSystemProcessorPerfInfo;
|
||||
};
|
||||
|
||||
typedef void (*CALLBACK_TEST_STARTED)(); //callback function to notify that the measured test is about to start
|
||||
typedef void (*CALLBACK_TEST_FINISHED)(); //callback function to notify that the measured test has just finished
|
||||
|
||||
class SystemInformation
|
||||
{
|
||||
public:
|
||||
string sComputerName;
|
||||
|
||||
SystemInformation()
|
||||
{
|
||||
char buffer[64];
|
||||
DWORD cb = _countof(buffer);
|
||||
BOOL fResult;
|
||||
|
||||
#pragma prefast(suppress:38020, "Yes, we're aware this is an ANSI API in a UNICODE project")
|
||||
fResult = GetComputerNameExA(ComputerNamePhysicalDnsHostname, buffer, &cb);
|
||||
if (fResult)
|
||||
{
|
||||
sComputerName = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
string SystemInformation::GetXml() const
|
||||
{
|
||||
string sXml("<System>\n");
|
||||
|
||||
// identify computer which ran the test
|
||||
sXml += "<ComputerName>";
|
||||
sXml += sComputerName;
|
||||
sXml += "</ComputerName>\n";
|
||||
|
||||
// identify tool version which performed the test
|
||||
sXml += "<Tool>\n";
|
||||
sXml += "<Version>" DISKSPD_NUMERIC_VERSION_STRING "</Version>\n";
|
||||
sXml += "<VersionDate>" DISKSPD_DATE_VERSION_STRING "</VersionDate>\n";
|
||||
sXml += "</Tool>\n";
|
||||
|
||||
sXml += "</System>\n";
|
||||
|
||||
return sXml;
|
||||
}
|
||||
};
|
||||
|
||||
struct Synchronization
|
||||
{
|
||||
ULONG ulStructSize; //size of the structure that the caller is aware of (to easier achieve backward compatibility in a future)
|
||||
HANDLE hStopEvent; //an event to be signalled if the scenario is to be stop before time ellapses
|
||||
HANDLE hStartEvent; //an event for signalling start
|
||||
CALLBACK_TEST_STARTED pfnCallbackTestStarted; //a function to be called if the measured test is about to start
|
||||
CALLBACK_TEST_FINISHED pfnCallbackTestFinished; //a function to be called as soon as the measrued test finishes
|
||||
};
|
||||
|
||||
#define STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, Field) ( \
|
||||
(NULL != (pSynch)) && \
|
||||
((pSynch)->ulStructSize >= offsetof(struct Synchronization, Field) + sizeof((pSynch)->Field)) \
|
||||
)
|
||||
|
||||
class Target
|
||||
{
|
||||
public:
|
||||
|
||||
Target() :
|
||||
_dwBlockSize(64 * 1024),
|
||||
_dwRequestCount(2),
|
||||
_ullBlockAlignment(64 * 1024),
|
||||
_fBlockAlignmentValid(false),
|
||||
_fUseRandomAccessPattern(false),
|
||||
_ullBaseFileOffset(0),
|
||||
_fParallelAsyncIO(false),
|
||||
_fInterlockedSequential(false),
|
||||
_fDisableOSCache(false),
|
||||
_fDisableAllCache(false),
|
||||
_fZeroWriteBuffers(false),
|
||||
_dwThreadsPerFile(1),
|
||||
_ullThreadStride(0),
|
||||
_fCreateFile(false),
|
||||
_fPrecreated(false),
|
||||
_ullFileSize(0),
|
||||
_ullMaxFileSize(0),
|
||||
_ulWriteRatio(0),
|
||||
_fUseBurstSize(false),
|
||||
_dwBurstSize(0),
|
||||
_dwThinkTime(0),
|
||||
_fThinkTime(false),
|
||||
_fSequentialScanHint(false),
|
||||
_fRandomAccessHint(false),
|
||||
_fUseLargePages(false),
|
||||
_ioPriorityHint(IoPriorityHintNormal),
|
||||
_dwThroughputBytesPerMillisecond(0),
|
||||
_cbRandomDataWriteBuffer(0),
|
||||
_sRandomDataWriteBufferSourcePath(),
|
||||
_pRandomDataWriteBuffer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void SetPath(string sPath) { _sPath = sPath; }
|
||||
string GetPath() const { return _sPath; }
|
||||
|
||||
void SetBlockSizeInBytes(DWORD dwBlockSize) { _dwBlockSize = dwBlockSize; }
|
||||
DWORD GetBlockSizeInBytes() const { return _dwBlockSize; }
|
||||
|
||||
void SetBlockAlignmentInBytes(UINT64 ullBlockAlignment)
|
||||
{
|
||||
_ullBlockAlignment = ullBlockAlignment;
|
||||
_fBlockAlignmentValid = true;
|
||||
}
|
||||
|
||||
UINT64 GetBlockAlignmentInBytes() const
|
||||
{
|
||||
return _fBlockAlignmentValid ? _ullBlockAlignment : _dwBlockSize;
|
||||
}
|
||||
|
||||
void SetUseRandomAccessPattern(bool fUseRandomAccessPattern) { _fUseRandomAccessPattern = fUseRandomAccessPattern; }
|
||||
bool GetUseRandomAccessPattern() const { return _fUseRandomAccessPattern; }
|
||||
|
||||
void SetBaseFileOffsetInBytes(UINT64 ullBaseFileOffset) { _ullBaseFileOffset = ullBaseFileOffset; }
|
||||
UINT64 GetBaseFileOffsetInBytes() const { return _ullBaseFileOffset; }
|
||||
|
||||
void SetSequentialScanHint(bool fSequentialScanHint) { _fSequentialScanHint = fSequentialScanHint; }
|
||||
bool GetSequentialScanHint() const { return _fSequentialScanHint; }
|
||||
|
||||
void SetRandomAccessHint(bool fRandomAccessHint) { _fRandomAccessHint = fRandomAccessHint; }
|
||||
bool GetRandomAccessHint() const { return _fRandomAccessHint; }
|
||||
|
||||
void SetUseLargePages(bool fUseLargePages) { _fUseLargePages = fUseLargePages; }
|
||||
bool GetUseLargePages() const { return _fUseLargePages; }
|
||||
|
||||
void SetRequestCount(DWORD dwRequestCount) { _dwRequestCount = dwRequestCount; }
|
||||
DWORD GetRequestCount() const { return _dwRequestCount; }
|
||||
|
||||
void SetDisableOSCache(bool fDisableOSCache) { _fDisableOSCache = fDisableOSCache; }
|
||||
bool GetDisableOSCache() const { return _fDisableOSCache; }
|
||||
|
||||
void SetDisableAllCache(bool fDisableAllCache) { _fDisableAllCache = fDisableAllCache; }
|
||||
bool GetDisableAllCache() const { return _fDisableAllCache; }
|
||||
|
||||
void SetZeroWriteBuffers(bool fZeroWriteBuffers) { _fZeroWriteBuffers = fZeroWriteBuffers; }
|
||||
bool GetZeroWriteBuffers() const { return _fZeroWriteBuffers; }
|
||||
|
||||
void SetRandomDataWriteBufferSize(UINT64 cbWriteBuffer) { _cbRandomDataWriteBuffer = cbWriteBuffer; }
|
||||
UINT64 GetRandomDataWriteBufferSize(void) const { return _cbRandomDataWriteBuffer; }
|
||||
|
||||
void SetRandomDataWriteBufferSourcePath(string sPath) { _sRandomDataWriteBufferSourcePath = sPath; }
|
||||
string GetRandomDataWriteBufferSourcePath() const { return _sRandomDataWriteBufferSourcePath; }
|
||||
|
||||
void SetUseBurstSize(bool fUseBurstSize) { _fUseBurstSize = fUseBurstSize; }
|
||||
bool GetUseBurstSize() const { return _fUseBurstSize; }
|
||||
|
||||
void SetBurstSize(DWORD dwBurstSize) { _dwBurstSize = dwBurstSize; }
|
||||
DWORD GetBurstSize() const { return _dwBurstSize; }
|
||||
|
||||
void SetThinkTime(DWORD dwThinkTime) { _dwThinkTime = dwThinkTime; }
|
||||
DWORD GetThinkTime() const { return _dwThinkTime; }
|
||||
|
||||
void SetEnableThinkTime(bool fEnable) { _fThinkTime = fEnable; }
|
||||
bool GetEnableThinkTime() const { return _fThinkTime; }
|
||||
|
||||
void SetThreadsPerFile(DWORD dwThreadsPerFile) { _dwThreadsPerFile = dwThreadsPerFile; }
|
||||
DWORD GetThreadsPerFile() const { return _dwThreadsPerFile; }
|
||||
|
||||
void SetCreateFile(bool fCreateFile) { _fCreateFile = fCreateFile; }
|
||||
bool GetCreateFile() const { return _fCreateFile; }
|
||||
|
||||
void SetFileSize(UINT64 ullFileSize) { _ullFileSize = ullFileSize; }
|
||||
UINT64 GetFileSize() const { return _ullFileSize; } // TODO: InBytes
|
||||
|
||||
void SetMaxFileSize(UINT64 ullMaxFileSize) { _ullMaxFileSize = ullMaxFileSize; }
|
||||
UINT64 GetMaxFileSize() const { return _ullMaxFileSize; }
|
||||
|
||||
void SetWriteRatio(UINT32 ulWriteRatio) { _ulWriteRatio = ulWriteRatio; }
|
||||
UINT32 GetWriteRatio() const { return _ulWriteRatio; }
|
||||
|
||||
void SetUseParallelAsyncIO(bool fParallelAsyncIO) { _fParallelAsyncIO = fParallelAsyncIO; }
|
||||
bool GetUseParallelAsyncIO() const { return _fParallelAsyncIO; }
|
||||
|
||||
void SetUseInterlockedSequential(bool fInterlockedSequential) { _fInterlockedSequential = fInterlockedSequential; }
|
||||
bool GetUseInterlockedSequential() const { return _fInterlockedSequential; }
|
||||
|
||||
void SetThreadStrideInBytes(UINT64 ullThreadStride) { _ullThreadStride = ullThreadStride; }
|
||||
UINT64 GetThreadStrideInBytes() const { return _ullThreadStride; }
|
||||
|
||||
void SetIOPriorityHint(PRIORITY_HINT _hint)
|
||||
{
|
||||
assert(_hint < MaximumIoPriorityHintType);
|
||||
_ioPriorityHint = _hint;
|
||||
}
|
||||
PRIORITY_HINT GetIOPriorityHint() const { return _ioPriorityHint; }
|
||||
|
||||
void SetPrecreated(bool fPrecreated) { _fPrecreated = fPrecreated; }
|
||||
bool GetPrecreated() const { return _fPrecreated; }
|
||||
|
||||
void SetThroughput(DWORD dwThroughputBytesPerMillisecond) { _dwThroughputBytesPerMillisecond = dwThroughputBytesPerMillisecond; }
|
||||
DWORD GetThroughputInBytesPerMillisecond() const { return _dwThroughputBytesPerMillisecond; }
|
||||
|
||||
string GetXml() const;
|
||||
|
||||
bool AllocateAndFillRandomDataWriteBuffer();
|
||||
void FreeRandomDataWriteBuffer();
|
||||
BYTE* GetRandomDataWriteBuffer();
|
||||
|
||||
private:
|
||||
string _sPath;
|
||||
DWORD _dwBlockSize;
|
||||
DWORD _dwRequestCount; // TODO: change the name to something more descriptive (OutstandingRequestCount?)
|
||||
|
||||
UINT64 _ullBlockAlignment;
|
||||
bool _fBlockAlignmentValid;
|
||||
bool _fUseRandomAccessPattern;
|
||||
|
||||
UINT64 _ullBaseFileOffset;
|
||||
bool _fParallelAsyncIO;
|
||||
bool _fInterlockedSequential;
|
||||
bool _fDisableOSCache;
|
||||
bool _fDisableAllCache;
|
||||
bool _fZeroWriteBuffers;
|
||||
DWORD _dwThreadsPerFile;
|
||||
UINT64 _ullThreadStride;
|
||||
|
||||
bool _fCreateFile;
|
||||
bool _fPrecreated; // used to track which files have been created before the first timespan and which have to be created later
|
||||
UINT64 _ullFileSize;
|
||||
UINT64 _ullMaxFileSize;
|
||||
UINT32 _ulWriteRatio;
|
||||
bool _fUseBurstSize; // TODO: "use" or "enable"?; since burst size must be specified with the think time, one variable should be sufficient
|
||||
DWORD _dwBurstSize; // number of IOs in a burst
|
||||
DWORD _dwThinkTime; // time to pause before issuing the next burst of IOs
|
||||
// TODO: could this be removed by using _dwThinkTime==0?
|
||||
bool _fThinkTime; //variable to decide whether to think between IOs (default is false)
|
||||
DWORD _dwThroughputBytesPerMillisecond; // set to 0 to disable throttling
|
||||
|
||||
bool _fSequentialScanHint; // open file with the FILE_FLAG_SEQUENTIAL_SCAN hint
|
||||
bool _fRandomAccessHint; // open file with the FILE_FLAG_RANDOM_ACCESS hint
|
||||
bool _fUseLargePages; // Use large pages for IO buffers
|
||||
|
||||
UINT64 _cbRandomDataWriteBuffer; // if > 0, then the write buffer should be filled with random data
|
||||
string _sRandomDataWriteBufferSourcePath; // file that should be used for filling the write buffer (if the path is not available, use a crypto provider)
|
||||
BYTE *_pRandomDataWriteBuffer; // a buffer used for write data when _cbWriteBuffer > 0; it's shared by all the threads working on this target
|
||||
|
||||
PRIORITY_HINT _ioPriorityHint;
|
||||
|
||||
bool _FillRandomDataWriteBuffer();
|
||||
|
||||
friend class UnitTests::ProfileUnitTests;
|
||||
friend class UnitTests::TargetUnitTests;
|
||||
};
|
||||
|
||||
class TimeSpan
|
||||
{
|
||||
public:
|
||||
TimeSpan() :
|
||||
_ulDuration(10),
|
||||
_ulWarmUp(5),
|
||||
_ulCoolDown(0),
|
||||
_ulRandSeed(0),
|
||||
_dwThreadCount(0),
|
||||
_fGroupAffinity(false),
|
||||
_fDisableAffinity(false),
|
||||
_fCompletionRoutines(false),
|
||||
_fMeasureLatency(false),
|
||||
_fCalculateIopsStdDev(false),
|
||||
_ulIoBucketDurationInMilliseconds(1000)
|
||||
{
|
||||
}
|
||||
|
||||
void AddAffinityAssignment(UINT32 ulAffinity)
|
||||
{
|
||||
_vAffinity.push_back(ulAffinity);
|
||||
}
|
||||
vector<UINT32> GetAffinityAssignments() const { return _vAffinity; }
|
||||
|
||||
void AddTarget(const Target& target)
|
||||
{
|
||||
_vTargets.push_back(Target(target));
|
||||
}
|
||||
vector<Target> GetTargets() const { return _vTargets; }
|
||||
|
||||
void SetDuration(UINT32 ulDuration) { _ulDuration = ulDuration; }
|
||||
UINT32 GetDuration() const { return _ulDuration; }
|
||||
|
||||
void SetWarmup(UINT32 ulWarmup) { _ulWarmUp = ulWarmup; }
|
||||
UINT32 GetWarmup() const { return _ulWarmUp; }
|
||||
|
||||
void SetCooldown(UINT32 ulCooldown) { _ulCoolDown = ulCooldown; }
|
||||
UINT32 GetCooldown() const { return _ulCoolDown; }
|
||||
|
||||
void SetRandSeed(UINT32 ulRandSeed) { _ulRandSeed = ulRandSeed; }
|
||||
UINT32 GetRandSeed() const { return _ulRandSeed; }
|
||||
|
||||
void SetThreadCount(DWORD dwThreadCount) { _dwThreadCount = dwThreadCount; }
|
||||
DWORD GetThreadCount() const { return _dwThreadCount; }
|
||||
|
||||
void SetGroupAffinity(bool fGroupAffinity) { _fGroupAffinity = fGroupAffinity; }
|
||||
bool GetGroupAffinity() const { return _fGroupAffinity; }
|
||||
|
||||
void SetDisableAffinity(bool fDisableAffinity) { _fDisableAffinity = fDisableAffinity; }
|
||||
bool GetDisableAffinity() const { return _fDisableAffinity; }
|
||||
|
||||
void SetCompletionRoutines(bool fCompletionRoutines) { _fCompletionRoutines = fCompletionRoutines; }
|
||||
bool GetCompletionRoutines() const { return _fCompletionRoutines; }
|
||||
|
||||
void SetMeasureLatency(bool fMeasureLatency) { _fMeasureLatency = fMeasureLatency; }
|
||||
bool GetMeasureLatency() const { return _fMeasureLatency; }
|
||||
|
||||
void SetCalculateIopsStdDev(bool fCalculateStdDev) { _fCalculateIopsStdDev = fCalculateStdDev; }
|
||||
bool GetCalculateIopsStdDev() const { return _fCalculateIopsStdDev; }
|
||||
|
||||
void SetIoBucketDurationInMilliseconds(UINT32 ulIoBucketDurationInMilliseconds) { _ulIoBucketDurationInMilliseconds = ulIoBucketDurationInMilliseconds; }
|
||||
UINT32 GetIoBucketDurationInMilliseconds() const { return _ulIoBucketDurationInMilliseconds; }
|
||||
|
||||
string GetXml() const;
|
||||
void MarkFilesAsPrecreated(const vector<string> vFiles);
|
||||
|
||||
private:
|
||||
vector<Target> _vTargets;
|
||||
UINT32 _ulDuration;
|
||||
UINT32 _ulWarmUp;
|
||||
UINT32 _ulCoolDown;
|
||||
UINT32 _ulRandSeed;
|
||||
DWORD _dwThreadCount;
|
||||
bool _fGroupAffinity;
|
||||
bool _fDisableAffinity;
|
||||
vector<UINT32> _vAffinity;
|
||||
bool _fCompletionRoutines;
|
||||
bool _fMeasureLatency;
|
||||
bool _fCalculateIopsStdDev;
|
||||
UINT32 _ulIoBucketDurationInMilliseconds;
|
||||
|
||||
friend class UnitTests::ProfileUnitTests;
|
||||
};
|
||||
|
||||
enum class ResultsFormat
|
||||
{
|
||||
Text,
|
||||
Xml
|
||||
};
|
||||
|
||||
enum class PrecreateFiles
|
||||
{
|
||||
None,
|
||||
UseMaxSize,
|
||||
OnlyFilesWithConstantSizes,
|
||||
OnlyFilesWithConstantOrZeroSizes
|
||||
};
|
||||
|
||||
class Profile
|
||||
{
|
||||
public:
|
||||
Profile() :
|
||||
_fVerbose(false),
|
||||
_dwProgress(0),
|
||||
_fEtwEnabled(false),
|
||||
_fEtwProcess(false),
|
||||
_fEtwThread(false),
|
||||
_fEtwImageLoad(false),
|
||||
_fEtwDiskIO(false),
|
||||
_fEtwMemoryPageFaults(false),
|
||||
_fEtwMemoryHardFaults(false),
|
||||
_fEtwNetwork(false),
|
||||
_fEtwRegistry(false),
|
||||
_fEtwUsePagedMemory(false),
|
||||
_fEtwUsePerfTimer(false),
|
||||
_fEtwUseSystemTimer(false),
|
||||
_fEtwUseCyclesCounter(false),
|
||||
_resultsFormat(ResultsFormat::Text),
|
||||
_precreateFiles(PrecreateFiles::None)
|
||||
{
|
||||
}
|
||||
|
||||
void AddTimeSpan(const TimeSpan& timeSpan)
|
||||
{
|
||||
_vTimeSpans.push_back(TimeSpan(timeSpan));
|
||||
}
|
||||
|
||||
const vector<TimeSpan>& GetTimeSpans() const { return _vTimeSpans; }
|
||||
|
||||
void SetVerbose(bool fVerbose) { _fVerbose = fVerbose; }
|
||||
bool GetVerbose() const { return _fVerbose; }
|
||||
|
||||
void SetProgress(DWORD dwProgress) { _dwProgress = dwProgress; }
|
||||
DWORD GetProgress() const { return _dwProgress; }
|
||||
|
||||
void SetCmdLine(string sCmdLine) { _sCmdLine = sCmdLine; }
|
||||
string GetCmdLine() const { return _sCmdLine; };
|
||||
|
||||
void SetResultsFormat(ResultsFormat format) { _resultsFormat = format; }
|
||||
ResultsFormat GetResultsFormat() const { return _resultsFormat; }
|
||||
|
||||
void SetPrecreateFiles(PrecreateFiles c) { _precreateFiles = c; }
|
||||
PrecreateFiles GetPrecreateFiles() const { return _precreateFiles; }
|
||||
|
||||
//ETW
|
||||
void SetEtwEnabled(bool fEtwEnabled) { _fEtwEnabled = fEtwEnabled; }
|
||||
void SetEtwProcess(bool fEtwProcess) { _fEtwProcess = fEtwProcess; }
|
||||
void SetEtwThread(bool fEtwThread) { _fEtwThread = fEtwThread; }
|
||||
void SetEtwImageLoad(bool fEtwImageLoad) { _fEtwImageLoad = fEtwImageLoad; }
|
||||
void SetEtwDiskIO(bool fEtwDiskIO) { _fEtwDiskIO = fEtwDiskIO; }
|
||||
void SetEtwMemoryPageFaults(bool fEtwMemoryPageFaults) { _fEtwMemoryPageFaults = fEtwMemoryPageFaults; }
|
||||
void SetEtwMemoryHardFaults(bool fEtwMemoryHardFaults) { _fEtwMemoryHardFaults = fEtwMemoryHardFaults; }
|
||||
void SetEtwNetwork(bool fEtwNetwork) { _fEtwNetwork = fEtwNetwork; }
|
||||
void SetEtwRegistry(bool fEtwRegistry) { _fEtwRegistry = fEtwRegistry; }
|
||||
void SetEtwUsePagedMemory(bool fEtwUsePagedMemory) { _fEtwUsePagedMemory = fEtwUsePagedMemory; }
|
||||
void SetEtwUsePerfTimer(bool fEtwUsePerfTimer) { _fEtwUsePerfTimer = fEtwUsePerfTimer; }
|
||||
void SetEtwUseSystemTimer(bool fEtwUseSystemTimer) { _fEtwUseSystemTimer = fEtwUseSystemTimer; }
|
||||
void SetEtwUseCyclesCounter(bool fEtwUseCyclesCounter) { _fEtwUseCyclesCounter = fEtwUseCyclesCounter; }
|
||||
|
||||
bool GetEtwEnabled() const { return _fEtwEnabled; }
|
||||
bool GetEtwProcess() const { return _fEtwProcess; }
|
||||
bool GetEtwThread() const { return _fEtwThread; }
|
||||
bool GetEtwImageLoad() const { return _fEtwImageLoad; }
|
||||
bool GetEtwDiskIO() const { return _fEtwDiskIO; }
|
||||
bool GetEtwMemoryPageFaults() const { return _fEtwMemoryPageFaults; }
|
||||
bool GetEtwMemoryHardFaults() const { return _fEtwMemoryHardFaults; }
|
||||
bool GetEtwNetwork() const { return _fEtwNetwork; }
|
||||
bool GetEtwRegistry() const { return _fEtwRegistry; }
|
||||
bool GetEtwUsePagedMemory() const { return _fEtwUsePagedMemory; }
|
||||
bool GetEtwUsePerfTimer() const { return _fEtwUsePerfTimer; }
|
||||
bool GetEtwUseSystemTimer() const { return _fEtwUseSystemTimer; }
|
||||
bool GetEtwUseCyclesCounter() const { return _fEtwUseCyclesCounter; }
|
||||
|
||||
string GetXml() const;
|
||||
bool Validate(bool fSingleSpec) const;
|
||||
void MarkFilesAsPrecreated(const vector<string> vFiles);
|
||||
|
||||
private:
|
||||
Profile(const Profile& T);
|
||||
|
||||
vector<TimeSpan>_vTimeSpans;
|
||||
bool _fVerbose;
|
||||
DWORD _dwProgress;
|
||||
string _sCmdLine;
|
||||
ResultsFormat _resultsFormat;
|
||||
PrecreateFiles _precreateFiles;
|
||||
|
||||
//ETW
|
||||
bool _fEtwEnabled;
|
||||
bool _fEtwProcess;
|
||||
bool _fEtwThread;
|
||||
bool _fEtwImageLoad;
|
||||
bool _fEtwDiskIO;
|
||||
bool _fEtwMemoryPageFaults;
|
||||
bool _fEtwMemoryHardFaults;
|
||||
bool _fEtwNetwork;
|
||||
bool _fEtwRegistry;
|
||||
bool _fEtwUsePagedMemory;
|
||||
bool _fEtwUsePerfTimer;
|
||||
bool _fEtwUseSystemTimer;
|
||||
bool _fEtwUseCyclesCounter;
|
||||
|
||||
friend class UnitTests::ProfileUnitTests;
|
||||
};
|
||||
|
||||
class ThreadParameters
|
||||
{
|
||||
public:
|
||||
ThreadParameters() :
|
||||
pProfile(nullptr),
|
||||
pTimeSpan(nullptr),
|
||||
pullSharedSequentialOffsets(nullptr),
|
||||
ulRandSeed(0),
|
||||
ulThreadNo(0),
|
||||
ulRelativeThreadNo(0)
|
||||
{
|
||||
}
|
||||
|
||||
const Profile *pProfile;
|
||||
const TimeSpan *pTimeSpan;
|
||||
|
||||
vector<Target> vTargets;
|
||||
vector<HANDLE> vhTargets;
|
||||
vector<UINT64> vullFileSizes;
|
||||
vector<BYTE *> vpDataBuffers;
|
||||
vector<OVERLAPPED> vOverlapped; // each target has RequestCount OVERLAPPED structures
|
||||
vector<size_t> vOverlappedIdToTargetId;
|
||||
vector<size_t> vFirstOverlappedIdForTargetId; //id of the first overlapped structure in the vOverlapped vector by target
|
||||
vector<IOOperation> vdwIoType; //as many as vOverlapped; used by the completion routines
|
||||
vector<UINT64> vIoStartTimes;
|
||||
|
||||
// For vanilla sequential access (-s):
|
||||
// Private per-thread offsets, incremented directly, indexed to number of targets
|
||||
vector<UINT64> vullPrivateSequentialOffsets;
|
||||
|
||||
// For interlocked sequential access (-si):
|
||||
// Pointers to offsets shared between threads, incremented with an interlocked op
|
||||
UINT64* pullSharedSequentialOffsets;
|
||||
|
||||
UINT32 ulRandSeed;
|
||||
UINT32 ulThreadNo;
|
||||
UINT32 ulRelativeThreadNo;
|
||||
|
||||
// accounting
|
||||
volatile bool *pfAccountingOn;
|
||||
PUINT64 pullStartTime;
|
||||
ThreadResults *pResults;
|
||||
|
||||
//group affinity
|
||||
WORD wGroupNum;
|
||||
DWORD dwProcNum;
|
||||
GROUP_AFFINITY GroupAffinity;
|
||||
|
||||
HANDLE hStartEvent;
|
||||
|
||||
// TODO: check how it's used
|
||||
HANDLE hEndEvent; //used only in case of completion routines (not for IO Completion Ports)
|
||||
|
||||
bool AllocateAndFillBufferForTarget(const Target& target);
|
||||
BYTE* GetReadBuffer(size_t iTarget, size_t iRequest);
|
||||
BYTE* GetWriteBuffer(size_t iTarget, size_t iRequest);
|
||||
DWORD GetTotalRequestCount() const;
|
||||
|
||||
private:
|
||||
ThreadParameters(const ThreadParameters& T);
|
||||
};
|
||||
|
||||
class IResultParser
|
||||
{
|
||||
public:
|
||||
virtual string ParseResults(Profile& profile, const SystemInformation& system, vector<Results> vResults) = 0;
|
||||
virtual int GetTotalScore() = 0;
|
||||
virtual double GetAverageLatency() = 0;
|
||||
};
|
||||
Reference in New Issue
Block a user