Добавлена папка source в CristalDiskMark
This commit is contained in:
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
UINT64 PerfTimer::GetTime()
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
return li.QuadPart;
|
||||
}
|
||||
|
||||
UINT64 PerfTimer::_GetPerfTimerFreq()
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency(&li);
|
||||
return li.QuadPart;
|
||||
}
|
||||
|
||||
const UINT64 PerfTimer::TIMER_FREQ = _GetPerfTimerFreq();
|
||||
|
||||
double PerfTimer::PerfTimeToMicroseconds(const double perfTime)
|
||||
{
|
||||
return perfTime / (TIMER_FREQ / 1000000.0);
|
||||
}
|
||||
|
||||
double PerfTimer::PerfTimeToMilliseconds(const double perfTime)
|
||||
{
|
||||
return PerfTimeToMicroseconds(perfTime) / 1000;
|
||||
}
|
||||
|
||||
double PerfTimer::PerfTimeToSeconds(const double perfTime)
|
||||
{
|
||||
return PerfTimeToMilliseconds(perfTime) / 1000;
|
||||
}
|
||||
|
||||
double PerfTimer::PerfTimeToMicroseconds(const UINT64 perfTime)
|
||||
{
|
||||
return PerfTimeToMicroseconds(static_cast<double>(perfTime));
|
||||
}
|
||||
|
||||
double PerfTimer::PerfTimeToMilliseconds(const UINT64 perfTime)
|
||||
{
|
||||
return PerfTimeToMilliseconds(static_cast<double>(perfTime));
|
||||
}
|
||||
|
||||
double PerfTimer::PerfTimeToSeconds(const UINT64 perfTime)
|
||||
{
|
||||
return PerfTimeToSeconds(static_cast<double>(perfTime));
|
||||
}
|
||||
|
||||
UINT64 PerfTimer::MicrosecondsToPerfTime(const double microseconds)
|
||||
{
|
||||
return static_cast<UINT64>(TIMER_FREQ * (microseconds / 1000000.0));
|
||||
}
|
||||
|
||||
UINT64 PerfTimer::MillisecondsToPerfTime(const double milliseconds)
|
||||
{
|
||||
return static_cast<UINT64>(TIMER_FREQ * (milliseconds / 1000.0));
|
||||
}
|
||||
|
||||
UINT64 PerfTimer::SecondsToPerfTime(const double seconds)
|
||||
{
|
||||
return static_cast<UINT64>(TIMER_FREQ * seconds);
|
||||
}
|
||||
|
||||
string Util::DoubleToStringHelper(const double d)
|
||||
{
|
||||
char szFloatBuffer[100];
|
||||
sprintf_s(szFloatBuffer, _countof(szFloatBuffer), "%10.3lf", d);
|
||||
|
||||
return string(szFloatBuffer);
|
||||
}
|
||||
|
||||
string Target::GetXml() const
|
||||
{
|
||||
char buffer[4096];
|
||||
string sXml("<Target>\n");
|
||||
sXml += "<Path>" + _sPath + "</Path>\n";
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<BlockSize>%u</BlockSize>\n", _dwBlockSize);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<BaseFileOffset>%I64u</BaseFileOffset>\n", _ullBaseFileOffset);
|
||||
sXml += buffer;
|
||||
|
||||
sXml += _fSequentialScanHint ? "<SequentialScan>true</SequentialScan>\n" : "<SequentialScan>false</SequentialScan>\n";
|
||||
sXml += _fRandomAccessHint ? "<RandomAccess>true</RandomAccess>\n" : "<RandomAccess>false</RandomAccess>\n";
|
||||
sXml += _fUseLargePages ? "<UseLargePages>true</UseLargePages>\n" : "<UseLargePages>false</UseLargePages>\n";
|
||||
sXml += _fDisableAllCache ? "<DisableAllCache>true</DisableAllCache>\n" : "<DisableAllCache>false</DisableAllCache>\n";
|
||||
// normalize cache controls - disabling the OS cache is included if all caches are disabled,
|
||||
// so specifying it twice is not neccesary (this generates a warning on the cmdline)
|
||||
if (!_fDisableAllCache)
|
||||
{
|
||||
sXml += _fDisableOSCache ? "<DisableOSCache>true</DisableOSCache>\n" : "<DisableOSCache>false</DisableOSCache>\n";
|
||||
}
|
||||
|
||||
sXml += "<WriteBufferContent>\n";
|
||||
if (_fZeroWriteBuffers)
|
||||
{
|
||||
sXml += "<Pattern>zero</Pattern>\n";
|
||||
}
|
||||
else if (_cbRandomDataWriteBuffer == 0)
|
||||
{
|
||||
sXml += "<Pattern>sequential</Pattern>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
sXml += "<Pattern>random</Pattern>\n";
|
||||
sXml += "<RandomDataSource>\n";
|
||||
sprintf_s(buffer, _countof(buffer), "<SizeInBytes>%I64u</SizeInBytes>\n", _cbRandomDataWriteBuffer);
|
||||
sXml += buffer;
|
||||
if (_sRandomDataWriteBufferSourcePath != "")
|
||||
{
|
||||
sXml += "<FilePath>" + _sRandomDataWriteBufferSourcePath + "</FilePath>\n";
|
||||
}
|
||||
sXml += "</RandomDataSource>\n";
|
||||
}
|
||||
sXml += "</WriteBufferContent>\n";
|
||||
|
||||
sXml += _fParallelAsyncIO ? "<ParallelAsyncIO>true</ParallelAsyncIO>\n" : "<ParallelAsyncIO>false</ParallelAsyncIO>\n";
|
||||
|
||||
if (_fUseBurstSize)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<BurstSize>%u</BurstSize>\n", _dwBurstSize);
|
||||
sXml += buffer;
|
||||
}
|
||||
|
||||
if (_fThinkTime)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<ThinkTime>%u</ThinkTime>\n", _dwThinkTime);
|
||||
sXml += buffer;
|
||||
}
|
||||
|
||||
if (_fCreateFile)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<FileSize>%I64u</FileSize>\n", _ullFileSize);
|
||||
sXml += buffer;
|
||||
}
|
||||
|
||||
// If XML contains <Random>, <StrideSize> is ignored
|
||||
if (_fUseRandomAccessPattern)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<Random>%I64u</Random>\n", GetBlockAlignmentInBytes());
|
||||
sXml += buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<StrideSize>%I64u</StrideSize>\n", GetBlockAlignmentInBytes());
|
||||
sXml += buffer;
|
||||
|
||||
sXml += _fInterlockedSequential ?
|
||||
"<InterlockedSequential>true</InterlockedSequential>\n" :
|
||||
"<InterlockedSequential>false</InterlockedSequential>\n";
|
||||
}
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<ThreadStride>%I64u</ThreadStride>\n", _ullThreadStride);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<MaxFileSize>%I64u</MaxFileSize>\n", _ullMaxFileSize);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<RequestCount>%u</RequestCount>\n", _dwRequestCount);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<WriteRatio>%u</WriteRatio>\n", _ulWriteRatio);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<Throughput>%u</Throughput>\n", _dwThroughputBytesPerMillisecond);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<ThreadsPerFile>%u</ThreadsPerFile>\n", _dwThreadsPerFile);
|
||||
sXml += buffer;
|
||||
|
||||
if (_ioPriorityHint == IoPriorityHintVeryLow)
|
||||
{
|
||||
sXml += "<IOPriority>1</IOPriority>\n";
|
||||
}
|
||||
else if (_ioPriorityHint == IoPriorityHintLow)
|
||||
{
|
||||
sXml += "<IOPriority>2</IOPriority>\n";
|
||||
}
|
||||
else if (_ioPriorityHint == IoPriorityHintNormal)
|
||||
{
|
||||
sXml += "<IOPriority>3</IOPriority>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
sXml += "<IOPriority>* UNSUPPORTED *</IOPriority>\n";
|
||||
}
|
||||
|
||||
sXml += "</Target>\n";
|
||||
|
||||
|
||||
return sXml;
|
||||
}
|
||||
|
||||
bool Target::_FillRandomDataWriteBuffer()
|
||||
{
|
||||
assert(_pRandomDataWriteBuffer != nullptr);
|
||||
bool fOk = true;
|
||||
size_t cb = static_cast<size_t>(GetRandomDataWriteBufferSize());
|
||||
if (GetRandomDataWriteBufferSourcePath() == "")
|
||||
{
|
||||
// fill buffer with random data
|
||||
for (size_t i = 0; i < cb; i++)
|
||||
{
|
||||
_pRandomDataWriteBuffer[i] = (rand() % 256);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fill buffer from file
|
||||
HANDLE hFile = CreateFile(GetRandomDataWriteBufferSourcePath().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
UINT64 cbLeftToRead = GetRandomDataWriteBufferSize();
|
||||
BYTE *pBuffer = _pRandomDataWriteBuffer;
|
||||
bool fReadSuccess = true;
|
||||
while (fReadSuccess && cbLeftToRead > 0)
|
||||
{
|
||||
DWORD cbToRead = static_cast<DWORD>(min(64 * 1024, cbLeftToRead));
|
||||
DWORD cbRead;
|
||||
fReadSuccess = ((ReadFile(hFile, pBuffer, cbToRead, &cbRead, nullptr) == TRUE) && (cbRead > 0));
|
||||
pBuffer += cbRead;
|
||||
}
|
||||
|
||||
// if the file is smaller than the buffer, repeat its content
|
||||
BYTE *pSource = _pRandomDataWriteBuffer;
|
||||
const BYTE *pPastEnd = pSource + GetRandomDataWriteBufferSize();
|
||||
while (pBuffer < pPastEnd)
|
||||
{
|
||||
*pBuffer++ = *pSource++;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
fOk = false;
|
||||
// TODO: print error message?
|
||||
}
|
||||
}
|
||||
return fOk;
|
||||
}
|
||||
|
||||
bool Target::AllocateAndFillRandomDataWriteBuffer()
|
||||
{
|
||||
assert(_pRandomDataWriteBuffer == nullptr);
|
||||
bool fOk = true;
|
||||
size_t cb = static_cast<size_t>(GetRandomDataWriteBufferSize());
|
||||
assert(cb > 0);
|
||||
|
||||
// TODO: make sure the size if <= max value for size_t
|
||||
/// CrystalDiskMark 4 does not support Large Page
|
||||
if (false && GetUseLargePages())
|
||||
{
|
||||
/// size_t cbMinLargePage = GetLargePageMinimum();
|
||||
/// size_t cbRoundedSize = (cb + cbMinLargePage - 1) & ~(cbMinLargePage - 1);
|
||||
/// _pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cb, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
fOk = (_pRandomDataWriteBuffer != nullptr);
|
||||
if (fOk)
|
||||
{
|
||||
fOk = _FillRandomDataWriteBuffer();
|
||||
}
|
||||
return fOk;
|
||||
}
|
||||
|
||||
void Target::FreeRandomDataWriteBuffer()
|
||||
{
|
||||
if (nullptr != _pRandomDataWriteBuffer)
|
||||
{
|
||||
VirtualFree(_pRandomDataWriteBuffer, 0, MEM_RELEASE);
|
||||
_pRandomDataWriteBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BYTE* Target::GetRandomDataWriteBuffer()
|
||||
{
|
||||
size_t cbBuffer = static_cast<size_t>(GetRandomDataWriteBufferSize());
|
||||
size_t cbBlock = GetBlockSizeInBytes();
|
||||
|
||||
// leave enough bytes in the buffer for one block
|
||||
size_t randomOffset = rand() % (cbBuffer - (cbBlock - 1));
|
||||
|
||||
bool fUnbufferedIO = (GetDisableOSCache() || GetDisableAllCache());
|
||||
if (fUnbufferedIO)
|
||||
{
|
||||
// for unbuffered IO, offset in the buffer needs to be DWORD-aligned
|
||||
const size_t cbAlignment = 4;
|
||||
randomOffset -= (randomOffset % cbAlignment);
|
||||
}
|
||||
|
||||
BYTE *pBuffer = reinterpret_cast<BYTE*>(reinterpret_cast<ULONG_PTR>(_pRandomDataWriteBuffer)+randomOffset);
|
||||
|
||||
// unbuffered IO needs aligned addresses
|
||||
assert(!fUnbufferedIO || (reinterpret_cast<ULONG_PTR>(pBuffer) % 4 == 0));
|
||||
|
||||
assert(pBuffer >= _pRandomDataWriteBuffer);
|
||||
assert(pBuffer <= _pRandomDataWriteBuffer + GetRandomDataWriteBufferSize() - GetBlockSizeInBytes());
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
string TimeSpan::GetXml() const
|
||||
{
|
||||
string sXml("<TimeSpan>\n");
|
||||
char buffer[4096];
|
||||
|
||||
sXml += _fCompletionRoutines ? "<CompletionRoutines>true</CompletionRoutines>\n" : "<CompletionRoutines>false</CompletionRoutines>\n";
|
||||
sXml += _fMeasureLatency ? "<MeasureLatency>true</MeasureLatency>\n" : "<MeasureLatency>false</MeasureLatency>\n";
|
||||
sXml += _fCalculateIopsStdDev ? "<CalculateIopsStdDev>true</CalculateIopsStdDev>\n" : "<CalculateIopsStdDev>false</CalculateIopsStdDev>\n";
|
||||
sXml += _fDisableAffinity ? "<DisableAffinity>true</DisableAffinity>\n" : "<DisableAffinity>false</DisableAffinity>\n";
|
||||
sXml += _fGroupAffinity ? "<GroupAffinity>true</GroupAffinity>\n" : "<GroupAffinity>false</GroupAffinity>\n";
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<Duration>%u</Duration>\n", _ulDuration);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<Warmup>%u</Warmup>\n", _ulWarmUp);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<Cooldown>%u</Cooldown>\n", _ulCoolDown);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<ThreadCount>%u</ThreadCount>\n", _dwThreadCount);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<IoBucketDuration>%u</IoBucketDuration>\n", _ulIoBucketDurationInMilliseconds);
|
||||
sXml += buffer;
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<RandSeed>%u</RandSeed>\n", _ulRandSeed);
|
||||
sXml += buffer;
|
||||
|
||||
if (_vAffinity.size() > 0)
|
||||
{
|
||||
sXml += "<Affinity>\n";
|
||||
for (auto a : _vAffinity)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer), "<AffinityAssignment>%u</AffinityAssignment>\n", a);
|
||||
sXml += buffer;
|
||||
}
|
||||
sXml += "</Affinity>\n";
|
||||
}
|
||||
|
||||
sXml += "<Targets>\n";
|
||||
for (const auto& target : _vTargets)
|
||||
{
|
||||
sXml += target.GetXml();
|
||||
}
|
||||
sXml += "</Targets>\n";
|
||||
sXml += "</TimeSpan>\n";
|
||||
return sXml;
|
||||
}
|
||||
|
||||
void TimeSpan::MarkFilesAsPrecreated(const vector<string> vFiles)
|
||||
{
|
||||
for (auto sFile : vFiles)
|
||||
{
|
||||
for (auto pTarget = _vTargets.begin(); pTarget != _vTargets.end(); pTarget++)
|
||||
{
|
||||
if (sFile == pTarget->GetPath())
|
||||
{
|
||||
pTarget->SetPrecreated(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string Profile::GetXml() const
|
||||
{
|
||||
string sXml("<Profile>\n");
|
||||
char buffer[4096];
|
||||
|
||||
sprintf_s(buffer, _countof(buffer), "<Progress>%u</Progress>\n", _dwProgress);
|
||||
sXml += buffer;
|
||||
|
||||
if (_resultsFormat == ResultsFormat::Text)
|
||||
{
|
||||
sXml += "<ResultFormat>text</ResultFormat>\n";
|
||||
}
|
||||
else if (_resultsFormat == ResultsFormat::Xml)
|
||||
{
|
||||
sXml += "<ResultFormat>xml</ResultFormat>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
sXml += "<ResultFormat>* UNSUPPORTED *</ResultFormat>\n";
|
||||
}
|
||||
|
||||
sXml += _fVerbose ? "<Verbose>true</Verbose>\n" : "<Verbose>false</Verbose>\n";
|
||||
if (_precreateFiles == PrecreateFiles::UseMaxSize)
|
||||
{
|
||||
sXml += "<PrecreateFiles>UseMaxSize</PrecreateFiles>\n";
|
||||
}
|
||||
else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantSizes)
|
||||
{
|
||||
sXml += "<PrecreateFiles>CreateOnlyFilesWithConstantSizes</PrecreateFiles>\n";
|
||||
}
|
||||
else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes)
|
||||
{
|
||||
sXml += "<PrecreateFiles>CreateOnlyFilesWithConstantOrZeroSizes</PrecreateFiles>\n";
|
||||
}
|
||||
|
||||
if (_fEtwEnabled)
|
||||
{
|
||||
sXml += _fEtwProcess ? "<Process>true</Process>\n" : "<Process>false</Process>\n";
|
||||
sXml += _fEtwThread ? "<Thread>true</Thread>\n" : "<Thread>false</Thread>\n";
|
||||
sXml += _fEtwImageLoad ? "<ImageLoad>true</ImageLoad>\n" : "<ImageLoad>false</ImageLoad>\n";
|
||||
sXml += _fEtwDiskIO ? "<DiskIO>true</DiskIO>\n" : "<DiskIO>false</DiskIO>\n";
|
||||
sXml += _fEtwMemoryPageFaults ? "<MemoryPageFaults>true</MemoryPageFaults>\n" : "<MemoryPageFaults>false</MemoryPageFaults>\n";
|
||||
sXml += _fEtwMemoryHardFaults ? "<MemoryHardFaults>true</MemoryHardFaults>\n" : "<MemoryHardFaults>false</MemoryHardFaults>\n";
|
||||
sXml += _fEtwNetwork ? "<Network>true</Network>\n" : "<Network>false</Network>\n";
|
||||
sXml += _fEtwRegistry ? "<Registry>true</Registry>\n" : "<Registry>false</Registry>\n";
|
||||
sXml += _fEtwUsePagedMemory ? "<UsePagedMemory>true</UsePagedMemory>\n" : "<UsePagedMemory>false</UsePagedMemory>\n";
|
||||
sXml += _fEtwUsePerfTimer ? "<UsePerfTimer>true</UsePerfTimer>\n" : "<UsePerfTimer>false</UsePerfTimer>\n";
|
||||
sXml += _fEtwUseSystemTimer ? "<UseSystemTimer>true</UseSystemTimer>\n" : "<UseSystemTimer>false</UseSystemTimer>\n";
|
||||
sXml += _fEtwUseCyclesCounter ? "<UseCyclesCounter>true</UseCyclesCounter>\n" : "<UseCyclesCounter>false</UseCyclesCounter>\n";
|
||||
}
|
||||
|
||||
sXml += "<TimeSpans>\n";
|
||||
for (const auto& timespan : _vTimeSpans)
|
||||
{
|
||||
sXml += timespan.GetXml();
|
||||
}
|
||||
sXml += "</TimeSpans>\n";
|
||||
sXml += "</Profile>\n";
|
||||
return sXml;
|
||||
}
|
||||
|
||||
void Profile::MarkFilesAsPrecreated(const vector<string> vFiles)
|
||||
{
|
||||
for (auto pTimeSpan = _vTimeSpans.begin(); pTimeSpan != _vTimeSpans.end(); pTimeSpan++)
|
||||
{
|
||||
pTimeSpan->MarkFilesAsPrecreated(vFiles);
|
||||
}
|
||||
}
|
||||
|
||||
bool Profile::Validate(bool fSingleSpec) const
|
||||
{
|
||||
bool fOk = true;
|
||||
for (const auto& timeSpan : GetTimeSpans())
|
||||
{
|
||||
if (timeSpan.GetDisableAffinity() && timeSpan.GetAffinityAssignments().size() > 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: -n and -a parameters cannot be used together\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
for (const auto& target : timeSpan.GetTargets())
|
||||
{
|
||||
const bool targetHasMultipleThreads = (timeSpan.GetThreadCount() > 1) || (target.GetThreadsPerFile() > 1);
|
||||
|
||||
if (timeSpan.GetThreadCount() > 0 && target.GetThreadsPerFile() > 1)
|
||||
{
|
||||
fprintf(stderr, "ERROR: -F and -t parameters cannot be used together\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
if (target.GetDisableAllCache() && target.GetDisableOSCache())
|
||||
{
|
||||
fprintf(stderr, "WARNING: -S is included in the effect of -h, specifying both is not required\n");
|
||||
}
|
||||
|
||||
if (target.GetThroughputInBytesPerMillisecond() > 0 && timeSpan.GetCompletionRoutines())
|
||||
{
|
||||
fprintf(stderr, "ERROR: -g throughput control cannot be used with -x completion routines\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
// If burst size is specified think time must be specified and If think time is specified burst size should be non zero
|
||||
if ((target.GetThinkTime() == 0 && target.GetBurstSize() > 0) || (target.GetThinkTime() > 0 && target.GetBurstSize() == 0))
|
||||
{
|
||||
fprintf(stderr, "ERROR: need to specify -j<think time> with -i<burst size>\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
// FIXME: we can no longer do this check, because the target no longer
|
||||
// contains a property that uniquely identifies the case where "-s" or <StrideSize>
|
||||
// was passed.
|
||||
#if 0
|
||||
if (target.GetUseRandomAccessPattern() && target.GetEnableCustomStrideSize())
|
||||
{
|
||||
fprintf(stderr, "WARNING: -s is ignored if -r is provided\n");
|
||||
}
|
||||
#endif
|
||||
if (target.GetUseRandomAccessPattern())
|
||||
{
|
||||
if (target.GetThreadStrideInBytes() > 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: -T conflicts with -r\n");
|
||||
fOk = false;
|
||||
// although ullThreadStride==0 is a valid value, it's interpreted as "not provided" for this warning
|
||||
}
|
||||
|
||||
if (target.GetUseInterlockedSequential())
|
||||
{
|
||||
fprintf(stderr, "ERROR: -si conflicts with -r\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
if (target.GetUseParallelAsyncIO())
|
||||
{
|
||||
fprintf(stderr, "ERROR: -p conflicts with -r\n");
|
||||
fOk = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.GetUseParallelAsyncIO() && target.GetRequestCount() == 1)
|
||||
{
|
||||
fprintf(stderr, "WARNING: -p does not have effect unless outstanding I/O count (-o) is > 1\n");
|
||||
}
|
||||
|
||||
if (timeSpan.GetRandSeed() > 0)
|
||||
{
|
||||
fprintf(stderr, "WARNING: -z is ignored if -r is not provided\n");
|
||||
// although ulRandSeed==0 is a valid value, it's interpreted as "not provided" for this warning
|
||||
}
|
||||
|
||||
if (target.GetUseInterlockedSequential())
|
||||
{
|
||||
if (target.GetThreadStrideInBytes() > 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: -si conflicts with -T\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
if (target.GetUseParallelAsyncIO())
|
||||
{
|
||||
fprintf(stderr, "ERROR: -si conflicts with -p\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
if (!targetHasMultipleThreads)
|
||||
{
|
||||
fprintf(stderr, "WARNING: single-threaded test, -si ignored\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetHasMultipleThreads && !target.GetThreadStrideInBytes())
|
||||
{
|
||||
fprintf(stderr, "WARNING: target access pattern will not be sequential, consider -si\n");
|
||||
}
|
||||
|
||||
if (!targetHasMultipleThreads && target.GetThreadStrideInBytes())
|
||||
{
|
||||
fprintf(stderr, "ERROR: -T has no effect unless multiple threads per target are used\n");
|
||||
fOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target.GetRandomDataWriteBufferSize() > 0)
|
||||
{
|
||||
if (target.GetRandomDataWriteBufferSize() < target.GetBlockSizeInBytes())
|
||||
{
|
||||
fprintf(stderr, "ERROR: custom write buffer (-Z) is smaller than the block size. Write buffer size: %I64u block size: %u\n",
|
||||
target.GetRandomDataWriteBufferSize(),
|
||||
target.GetBlockSizeInBytes());
|
||||
fOk = false;
|
||||
}
|
||||
}
|
||||
|
||||
// in the cases where there is only a single configuration specified for each target (e.g., cmdline),
|
||||
// currently there are no validations specific to individual targets (e.g., pre-existing files)
|
||||
// so we can stop validation now. this allows us to only warn/error once, as opposed to repeating
|
||||
// it for each target.
|
||||
if (fSingleSpec)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fOk;
|
||||
}
|
||||
|
||||
bool ThreadParameters::AllocateAndFillBufferForTarget(const Target& target)
|
||||
{
|
||||
bool fOk = true;
|
||||
BYTE *pDataBuffer = nullptr;
|
||||
size_t cbDataBuffer = target.GetBlockSizeInBytes() * target.GetRequestCount();
|
||||
|
||||
/// CrystalDiskMark 4 does not support Large Page
|
||||
if (false && target.GetUseLargePages())
|
||||
{
|
||||
/// size_t cbMinLargePage = GetLargePageMinimum();
|
||||
/// size_t cbRoundedSize = (cbDataBuffer + cbMinLargePage - 1) & ~(cbMinLargePage - 1);
|
||||
/// pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbDataBuffer, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
fOk = (pDataBuffer != nullptr);
|
||||
|
||||
//fill buffer (useful only for write tests)
|
||||
if (fOk && target.GetWriteRatio() > 0)
|
||||
{
|
||||
if (target.GetZeroWriteBuffers())
|
||||
{
|
||||
memset(pDataBuffer, 0, cbDataBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < cbDataBuffer; i++)
|
||||
{
|
||||
pDataBuffer[i] = (BYTE)(i % 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fOk)
|
||||
{
|
||||
vpDataBuffers.push_back(pDataBuffer);
|
||||
}
|
||||
|
||||
return fOk;
|
||||
}
|
||||
|
||||
BYTE* ThreadParameters::GetReadBuffer(size_t iTarget, size_t iRequest)
|
||||
{
|
||||
return vpDataBuffers[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes());
|
||||
}
|
||||
|
||||
BYTE* ThreadParameters::GetWriteBuffer(size_t iTarget, size_t iRequest)
|
||||
{
|
||||
BYTE *pBuffer = nullptr;
|
||||
|
||||
Target& target(vTargets[iTarget]);
|
||||
size_t cb = static_cast<size_t>(target.GetRandomDataWriteBufferSize());
|
||||
if (cb == 0)
|
||||
{
|
||||
pBuffer = vpDataBuffers[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuffer = target.GetRandomDataWriteBuffer();
|
||||
}
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
DWORD ThreadParameters::GetTotalRequestCount() const
|
||||
{
|
||||
DWORD cRequests = 0;
|
||||
|
||||
for (const auto& t : vTargets)
|
||||
{
|
||||
cRequests += t.GetRequestCount();
|
||||
}
|
||||
|
||||
return cRequests;
|
||||
}
|
||||
Reference in New Issue
Block a user