Добавлена папка source в CristalDiskMark

This commit is contained in:
2026-05-29 13:04:54 +07:00
commit bdc2295ee4
240 changed files with 94035 additions and 0 deletions
@@ -0,0 +1,73 @@
/*
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 "Common.h"
namespace UnitTests { class CmdLineParserUnitTests; }
class CmdLineParser
{
public:
CmdLineParser();
~CmdLineParser();
bool ParseCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, SystemInformation *pSystem = nullptr);
private:
bool _ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, bool& fXMLProfile);
bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile, vector<Target> *pvSubstTargets);
bool _ParseETWParameter(const char *arg, Profile *pProfile);
bool _ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode );
bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan);
bool _ParseRandomDistribution(const char *arg, vector<Target>& vTargets);
void _DisplayUsageInfo(const char *pszFilename) const;
bool _GetSizeInBytes(const char *pszSize, UINT64& ullSize, const char **pszRest) const;
bool _GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath);
static bool _IsSwitchChar(const char c) { return (c == '/' || c == '-'); }
enum class ParseState {
Unknown,
True,
False,
Bad
};
DWORD _dwBlockSize; // block size; other parameters may be stated in blocks
// so the block size is needed to process them
UINT32 _ulWriteRatio; // default percentage of write requests
HANDLE _hEventStarted; // event signalled to notify that the actual (measured) test is to be started
HANDLE _hEventFinished; // event signalled to notify that the actual test has finished
friend class UnitTests::CmdLineParserUnitTests;
};
@@ -0,0 +1,38 @@
/*
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.
*/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include <tchar.h>
#include <stdio.h>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,330 @@
/*
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 <map>
#include <unordered_map>
#include <string>
#include <sstream>
#include <limits>
#include <cmath>
// Plain min/max macros from common headers will interfere with std::numeric_limits
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
template<typename T>
class Histogram
{
private:
mutable std::unordered_map<T, unsigned> _data;
mutable unsigned _samples;
mutable std::map<T, unsigned> _sdata;
mutable unsigned _ssamples;
// Save most recent percentile/iterator/nth-distance query. If the next is strictly >= it allows
// an efficient forward iteration through an ascending set of queries.
mutable double _lastptile;
mutable unsigned _lastptilen;
mutable decltype(_sdata.cbegin()) _lastptilepos;
// A histogram starts writable/unsealed and automatically seals after the first read operation.
// Subsequent writes which add data restart from empty.
void _SealData() const
{
if (!_data.empty())
{
_sdata.clear();
_sdata = std::map<T, unsigned>(_data.cbegin(), _data.cend());
_ssamples = _samples;
// invalid ptile > 1; first ptile query will initialize
_lastptile = 1.1;
_data.clear();
_samples = 0;
}
}
public:
Histogram()
: _samples(0),
_ssamples(0)
{}
void Clear()
{
_data.clear();
_samples = 0;
_sdata.clear();
_ssamples = 0;
}
void Add(T v)
{
_data[v]++;
_samples++;
}
void Merge(const Histogram<T> &other)
{
for (auto i : other._data)
{
_data[ i.first ] += i.second;
}
_samples += other._samples;
}
T GetMin() const
{
_SealData();
// Default low if empty
if (!_ssamples)
{
return std::numeric_limits<T>::min();
}
return _sdata.cbegin()->first;
}
T GetMax() const
{
_SealData();
// Default low if empty
if (!_ssamples)
{
return std::numeric_limits<T>::min();
}
return _sdata.crbegin()->first;
}
unsigned GetSampleBuckets() const
{
return (unsigned) (_samples ? _data.size() : _sdata.size());
}
unsigned GetSampleSize() const
{
return _samples ? _samples : _ssamples;
}
T GetPercentile(double p) const
{
if ((p < 0.0) || (p > 1.0))
{
throw std::invalid_argument("Percentile must be >= 0 and <= 1");
}
_SealData();
// Default low if empty
if (!_ssamples)
{
return std::numeric_limits<T>::min();
}
const double target = p * _ssamples;
// Default to beginning; n is the number of samples iterated over so far
unsigned n = 0;
auto pos = _sdata.cbegin();
// Resume from last?
if (p >= _lastptile)
{
n = _lastptilen;
pos = _lastptilepos;
}
while (pos != _sdata.cend())
{
if (n + pos->second >= target)
{
// Save position. Note the pre-incremented distance through the histogram
// must be saved in case next is still in the same bucket.
_lastptile = p;
_lastptilen = n;
_lastptilepos = pos;
return pos->first;
}
n += pos->second;
++pos;
}
throw std::overflow_error("overran end trying to find percentile");
}
T GetPercentile(int p) const
{
return GetPercentile(static_cast<double>(p) / 100);
}
T GetMedian() const
{
return GetPercentile(0.5);
}
double GetStdDev() const { return GetStandardDeviation(); }
double GetAvg() const { return GetMean(); }
double GetMean() const
{
_SealData();
// Default low if empty
if (!_ssamples)
{
return std::numeric_limits<T>::min();
}
double sum(0);
for (const auto i : _sdata)
{
double bucket_val =
static_cast<double>(i.first) * i.second / _ssamples;
if (sum + bucket_val < 0)
{
throw std::overflow_error("while trying to accumulate sum");
}
sum += bucket_val;
}
return sum;
}
double GetStandardDeviation() const
{
double mean(GetMean());
double ssd(0);
for (const auto i : _sdata)
{
double dev = static_cast<double>(i.first) - mean;
double sqdev = dev * dev;
ssd += i.second * sqdev;
}
return sqrt(ssd / _ssamples);
}
std::string GetHistogramCsv(const unsigned bins) const
{
return GetHistogramCsv(bins, GetMin(), GetMax());
}
std::string GetHistogramCsv(const unsigned bins, const T LOW, const T HIGH) const
{
_SealData();
// ISSUE-REVIEW
// Currently bins are defined as strictly less-than
// their upper limit, with the exception of the last
// bin. Otherwise where would I put the max value?
const double binSize = static_cast<double>((HIGH - LOW) / bins);
double limit = static_cast<double>(LOW);
std::ostringstream os;
os.precision(std::numeric_limits<T>::digits10);
auto pos = _sdata.cbegin();
unsigned cumulative = 0;
for (unsigned bin = 1; bin <= bins; ++bin)
{
unsigned count = 0;
limit += binSize;
while (pos != _sdata.end() &&
(pos->first < limit || bin == bins))
{
count += pos->second;
++pos;
}
cumulative += count;
os << limit << "," << count << "," << cumulative << std::endl;
}
return os.str();
}
std::string GetRawCsv() const
{
_SealData();
std::ostringstream os;
os.precision(std::numeric_limits<T>::digits10);
for (const auto i : _sdata)
{
os << i.first << "," << i.second << std::endl;
}
return os.str();
}
std::string GetRaw() const
{
_SealData();
std::ostringstream os;
for (const auto i : _sdata)
{
os << i.second << " " << i.first << std::endl;
}
return os.str();
}
};
#pragma pop_macro("min")
#pragma pop_macro("max")
@@ -0,0 +1,84 @@
/*
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
#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <Evntrace.h> //ETW
#include <Winternl.h> //ntdll.dll
void PrintError(const char *format, ...);
namespace UnitTests
{
class IORequestGeneratorUnitTests;
}
class IORequestGenerator
{
public:
IORequestGenerator() :
_hNTDLL(nullptr)
{
}
//bool GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization *pSynch);
/// for CrystalDiskMark
bool GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization* pSynch, int* totalScore, double* averageLatency);
private:
struct CreateFileParameters
{
string sPath;
UINT64 ullFileSize;
bool fZeroWriteBuffers;
};
bool _GenerateRequestsForTimeSpan(const Profile& profile, const TimeSpan& timeSpan, Results& results, struct Synchronization *pSynch);
void _AbortWorkerThreads(HANDLE hStartEvent, vector<HANDLE>& vhThreads) const;
void _CloseOpenFiles(vector<HANDLE>& vhFiles) const;
DWORD _CreateDirectoryPath(const char *path) const;
bool _CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const;
bool _GetActiveGroupsAndProcs() const;
struct ETWSessionInfo _GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const;
bool _GetSystemPerfInfo(vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION>& vSPPI, bool fVerbose) const;
void _InitializeGlobalParameters();
bool _LoadDLLs();
bool _StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const;
void _TerminateWorkerThreads(vector<HANDLE>& vhThreads) const;
bool _ValidateProfile(const Profile& profile) const;
vector<struct CreateFileParameters> _GetFilesToPrecreate(const Profile& profile) const;
void _MarkFilesAsCreated(Profile& profile, const vector<struct CreateFileParameters>& vFiles) const;
bool _PrecreateFiles(Profile& profile) const;
HINSTANCE volatile _hNTDLL; //handle to ntdll.dll
friend class UnitTests::IORequestGeneratorUnitTests;
};
@@ -0,0 +1,228 @@
/*
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 "IoBucketizer.h"
#include <stdexcept>
/*
Calculating stddev using an online algorithm:
avg = sum(1..n, a[n]) / n
stddev = sqrt(sum(1..n, (a[n] - avg)^2) / n)
= sqrt(sum(1..n, a[n]^2 - 2 * a[n] * avg + avg^2) / n)
= sqrt((sum(1..n, a[n]^2) - 2 * avg * sum(1..n, a[n]) + n * avg^2) / n)
= sqrt((sum(1..n, a[n]^2) - 2 * (sum(1..n, a[n]) / n) * sum(1..n, a[n]) + n * (sum(1..n], a[n]) / n)^2) / n)
= sqrt((sum(1..n, a[n]^2) - (2 / n) * sum(1..n, a[n])^2 + (1 / n) * sum(1..n, a[n])^2) / n)
= sqrt((sum(1..n, a[n]^2) - (1 / n) * sum(1..n, a[n])^2) / n)
So if we track n, sum(a[n]) and sum(a[n]^2) we can calculate the stddev. This
is used to calculate the stddev of the latencies below.
*/
const unsigned __int64 INVALID_BUCKET_DURATION = 0;
IoBucketizer::IoBucketizer()
: _bucketDuration(INVALID_BUCKET_DURATION),
_validBuckets(0),
_totalBuckets(0)
{}
void IoBucketizer::Initialize(unsigned __int64 bucketDuration, size_t validBuckets)
{
if (_bucketDuration != INVALID_BUCKET_DURATION)
{
throw std::runtime_error("IoBucketizer has already been initialized");
}
if (bucketDuration == INVALID_BUCKET_DURATION)
{
throw std::invalid_argument("Bucket duration must be a positive integer");
}
_bucketDuration = bucketDuration;
_validBuckets = validBuckets;
_vBuckets.resize(_validBuckets);
}
void IoBucketizer::Add(unsigned __int64 ioCompletionTime, double ioDuration)
{
if (_bucketDuration == INVALID_BUCKET_DURATION)
{
throw std::runtime_error("IoBucketizer has not been initialized");
}
size_t bucketNumber = static_cast<size_t>(ioCompletionTime / _bucketDuration);
_totalBuckets = bucketNumber + 1;
if (bucketNumber >= _validBuckets)
{
return;
}
_vBuckets[bucketNumber].lfSumDuration += ioDuration;
_vBuckets[bucketNumber].lfSumSqrDuration += ioDuration * ioDuration;
if (_vBuckets[bucketNumber].ulCount == 0 ||
ioDuration < _vBuckets[bucketNumber].lfMinDuration)
{
_vBuckets[bucketNumber].lfMinDuration = ioDuration;
}
if (_vBuckets[bucketNumber].ulCount == 0 ||
ioDuration > _vBuckets[bucketNumber].lfMaxDuration)
{
_vBuckets[bucketNumber].lfMaxDuration = ioDuration;
}
_vBuckets[bucketNumber].ulCount++;
}
size_t IoBucketizer::GetNumberOfValidBuckets() const
{
return (_totalBuckets > _validBuckets ? _validBuckets : _totalBuckets);
}
unsigned int IoBucketizer::GetIoBucketCount(size_t bucketNumber) const
{
if (bucketNumber < _validBuckets)
{
return _vBuckets[bucketNumber].ulCount;
}
return 0;
}
double IoBucketizer::GetIoBucketMinDurationUsec(size_t bucketNumber) const
{
if (bucketNumber < _validBuckets)
{
return _vBuckets[bucketNumber].lfMinDuration;
}
return 0;
}
double IoBucketizer::GetIoBucketMaxDurationUsec(size_t bucketNumber) const
{
if (bucketNumber < _validBuckets)
{
return _vBuckets[bucketNumber].lfMaxDuration;
}
return 0;
}
double IoBucketizer::GetIoBucketAvgDurationUsec(size_t bucketNumber) const
{
if (bucketNumber < _validBuckets && _vBuckets[bucketNumber].ulCount != 0)
{
return _vBuckets[bucketNumber].lfSumDuration / static_cast<double>(_vBuckets[bucketNumber].ulCount);
}
return 0;
}
double IoBucketizer::GetIoBucketDurationStdDevUsec(size_t bucketNumber) const
{
if (bucketNumber < _validBuckets && _vBuckets[bucketNumber].ulCount != 0)
{
double sum_of_squares = _vBuckets[bucketNumber].lfSumSqrDuration;
double square_of_sum = _vBuckets[bucketNumber].lfSumDuration * _vBuckets[bucketNumber].lfSumDuration;
double count = static_cast<double>(_vBuckets[bucketNumber].ulCount);
double square_stddev = (sum_of_squares - (square_of_sum / count)) / count;
return sqrt(square_stddev);
}
return 0;
}
double IoBucketizer::_GetMeanIOPS() const
{
size_t numBuckets = GetNumberOfValidBuckets();
double sum = 0;
for (size_t i = 0; i < numBuckets; i++)
{
sum += static_cast<double>(_vBuckets[i].ulCount) / numBuckets;
}
return sum;
}
double IoBucketizer::GetStandardDeviationIOPS() const
{
size_t numBuckets = GetNumberOfValidBuckets();
if(numBuckets == 0)
{
return 0.0;
}
double mean = _GetMeanIOPS();
double ssd = 0;
for (size_t i = 0; i < numBuckets; i++)
{
double dev = static_cast<double>(_vBuckets[i].ulCount) - mean;
double sqdev = dev*dev;
ssd += sqdev;
}
return sqrt(ssd / numBuckets);
}
void IoBucketizer::Merge(const IoBucketizer& other)
{
if(other._vBuckets.size() > _vBuckets.size())
{
_vBuckets.resize(other._vBuckets.size());
}
for(size_t i = 0; i < other._vBuckets.size(); i++)
{
_vBuckets[i].ulCount += other._vBuckets[i].ulCount;
_vBuckets[i].lfSumDuration += other._vBuckets[i].lfSumDuration;
_vBuckets[i].lfSumSqrDuration += other._vBuckets[i].lfSumSqrDuration;
if (i >= _validBuckets ||
other._vBuckets[i].lfMinDuration < _vBuckets[i].lfMinDuration)
{
_vBuckets[i].lfMinDuration = other._vBuckets[i].lfMinDuration;
}
if (other._vBuckets[i].lfMaxDuration > _vBuckets[i].lfMaxDuration)
{
_vBuckets[i].lfMaxDuration = other._vBuckets[i].lfMaxDuration;
}
}
if (other._validBuckets > _validBuckets)
{
_validBuckets = other._validBuckets;
}
if (other._totalBuckets > _totalBuckets)
{
_totalBuckets = other._totalBuckets;
}
}
@@ -0,0 +1,73 @@
/*
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 <vector>
class IoBucketizer
{
public:
IoBucketizer();
void Initialize(unsigned __int64 bucketDuration, size_t validBuckets);
size_t GetNumberOfValidBuckets() const;
unsigned int GetIoBucketCount(size_t bucketNumber) const;
double GetIoBucketMinDurationUsec(size_t bucketNumber) const;
double GetIoBucketMaxDurationUsec(size_t bucketNumber) const;
double GetIoBucketAvgDurationUsec(size_t bucketNumber) const;
double GetIoBucketDurationStdDevUsec(size_t bucketNumber) const;
void Add(unsigned __int64 ioCompletionTime, double ioDuration);
double GetStandardDeviationIOPS() const;
void Merge(const IoBucketizer& other);
private:
double _GetMeanIOPS() const;
struct IoBucket {
IoBucket() :
ulCount(0),
lfMinDuration(0),
lfMaxDuration(0),
lfSumDuration(0),
lfSumSqrDuration(0)
{
}
unsigned int ulCount;
double lfMinDuration;
double lfMaxDuration;
double lfSumDuration;
double lfSumSqrDuration;
};
unsigned __int64 _bucketDuration;
size_t _validBuckets;
size_t _totalBuckets;
std::vector<IoBucket> _vBuckets;
};
@@ -0,0 +1,50 @@
/*
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>
//
// OverlappedQueue is a simple class that implements a queue for OVERLAPPED elements
//
class OverlappedQueue
{
public:
OverlappedQueue(void);
void Add(OVERLAPPED *pOverlapped);
bool IsEmpty(void) const;
OVERLAPPED * Remove(void);
size_t GetCount() const;
private:
OVERLAPPED *_pHead;
OVERLAPPED *_pTail;
size_t _cItems;
};
@@ -0,0 +1,76 @@
/*
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 "Common.h"
namespace UnitTests
{
class ResultParserUnitTests;
}
class ResultParser : public IResultParser
{
public:
string ParseResults(const Profile& profile, const SystemInformation& system, vector<Results> vResults);
string ParseProfile(const Profile& profile);
/// for CrystalDiskMark
int GetTotalScore();
double GetAverageLatency();
private:
void _DisplayFileSize(UINT64 fsize, UINT32 align = 0);
void _DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo);
void _DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters);
void _Print(const char *format, ...);
void _PrintProfile(const Profile& profile);
void _PrintSystemInfo(const SystemInformation& system);
void _PrintCpuUtilization(const Results& results, const SystemInformation& system);
enum class _SectionEnum {TOTAL, READ, WRITE};
void _PrintSectionFieldNames(const TimeSpan& timeSpan);
void _PrintSectionBorderLine(const TimeSpan& timeSpan);
void _PrintSection(_SectionEnum, const TimeSpan&, const Results&);
void _PrintLatencyPercentiles(const Results&);
void _PrintLatencyChart(const Histogram<float>& readLatencyHistogram,
const Histogram<float>& writeLatencyHistogram,
const Histogram<float>& totalLatencyHistogram);
void _PrintTimeSpan(const TimeSpan &timeSpan);
void _PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fUseRequestsPerFile, bool fCompletionRoutines);
void _PrintDistribution(DistributionType dT, const vector<DistributionRange>& v, char* spc);
void _PrintEffectiveDistributions(const Results& results);
void _PrintWaitStats(const Results& result);
string _sResult;
/// for CrystalDiskMark
int _totalScore;
double _averageLatency;
friend class UnitTests::ResultParserUnitTests;
};
@@ -0,0 +1,61 @@
/*
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>
// ThroughputMeter class assists in metering out throughput over
// time. The meter is started by calling Start() with the throughput
// to be simulated. GetSleepTime() returns 0 when the next IO can be issued.
// Adjust() is called to notify the ThroughputMeter about how many bytes were read/written.
class ThroughputMeter
{
public:
ThroughputMeter(void);
bool IsRunning(void) const;
void Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize);
DWORD GetSleepTime(void) const;
void Adjust(size_t cb);
private:
DWORD _GetThrottleTime(void) const;
bool _fRunning; // true = throughput monitoring is on
bool _fThrottle; // true = throttling is on
bool _fThink; // true = think time is enabled
ULONGLONG _cbCompleted; // completed IO
DWORD _cbBlockSize;
DWORD _cBytesPerMillisecond; // rate of throttling
ULONGLONG _ullStartTimestamp;
ULONGLONG _ullDelayUntil; // timestamp at which the next IO can be executed
DWORD _thinkTime; // time to sleep between burst of IOs
DWORD _burstSize; // number of IOs in a burst. meaningless if think time is zero
DWORD _cIO; // count of IOs in the current burst
};
@@ -0,0 +1,52 @@
/*
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.
*/
// 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_REVISION ""
#define DISKSPD_MAJOR 2
#define DISKSPD_MINOR 2
#define DISKSPD_BUILD 0
#define DISKSPD_QFE 0
#define DISKSPD_MAJORMINOR_VER_STR(x,y,z) #x "." #y "." #z
#define DISKSPD_MAJORMINOR_VERSION_STRING(x,y,z) DISKSPD_MAJORMINOR_VER_STR(x,y,z)
#define DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_MAJORMINOR_VERSION_STRING(DISKSPD_MAJOR, DISKSPD_MINOR, DISKSPD_BUILD)
#define DISKSPD_NUMERIC_VERSION_STRING DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_REVISION DISKSPD_RELEASE_TAG
#define DISKSPD_DATE_VERSION_STRING "2024/6/3"
@@ -0,0 +1,65 @@
/*
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 <MsXml6.h>
#include "Common.h"
class XmlProfileParser
{
public:
bool ParseFile(const char *pszPath, Profile *pProfile, vector<Target> *pvSubstTargets, HMODULE hModule);
private:
HRESULT _ParseEtw(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile);
HRESULT _ParseTimeSpans(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile, vector<pair<string, bool>>& vSubsts);
HRESULT _ParseTimeSpan(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector<pair<string, bool>>& vSubsts);
HRESULT _ParseTargets(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector<pair<string, bool>>& vSubsts);
HRESULT _ParseRandomDataSource(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _ParseWriteBufferContent(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _ParseThreadTargets(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _ParseThroughput(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _ParseThreadTarget(IXMLDOMNode *pXmlNode, ThreadTarget *pThreadTarget);
HRESULT _ParseAffinityAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan);
HRESULT _ParseAffinityGroupAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan);
HRESULT _ParseDistribution(IXMLDOMNode *pXmlNode, Target *pTarget);
HRESULT _SubstTarget(Target *pTarget, vector<pair<string, bool>>& vSubsts);
HRESULT _GetString(IXMLDOMNode *pXmlNode, const char *pszQuery, string *psValue) const;
HRESULT _GetUINT32(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT32 *pulValue) const;
HRESULT _GetUINT64(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT64 *pullValue) const;
HRESULT _GetDWORD(IXMLDOMNode *pXmlNode, const char *pszQuery, DWORD *pdwValue) const;
HRESULT _GetBool(IXMLDOMNode *pXmlNode, const char *pszQuery, bool *pfValue) const;
HRESULT _GetUINT32Attr(IXMLDOMNode *pXmlNode, const char *pszAttr, UINT32 *pulValue) const;
HRESULT _GetVerbose(IXMLDOMDocument2 *pXmlDoc, bool *pfVerbose);
HRESULT _GetProgress(IXMLDOMDocument2 *pXmlDoc, DWORD *pdwProgress);
};
@@ -0,0 +1,61 @@
/*
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 "Common.h"
class XmlResultParser: public IResultParser
{
public:
string ParseResults(const Profile& profile, const SystemInformation& system, vector<Results> vResults);
string ParseProfile(const Profile& profile);
/// for CrystalDiskMark
int GetTotalScore();
double GetAverageLatency();
private:
void _PrintCpuUtilization(const Results& results, const SystemInformation& system);
void _PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters);
void _PrintETWSessionInfo(struct ETWSessionInfo sessionInfo);
void _PrintLatencyPercentiles(const Results& results);
void _PrintTargetResults(const TargetResults& results);
void _PrintTargetLatency(const TargetResults& results);
void _PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs);
void _PrintOverallIops(const Results& results, UINT32 bucketTimeInMs);
void _PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs);
void _PrintWaitStats(const ThreadResults& threadResult);
void _PrintV(const char *format, va_list listArg);
void _Print(const char *format, ...);
void _PrintInc(const char *format, ...);
void _PrintDec(const char *format, ...);
string _sResult;
UINT32 _indent = 0;
};
@@ -0,0 +1,38 @@
/*
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.
*/
#ifndef __DISKSPD_ERRORS_H
#define __DISKSPD_ERRORS_H
#define ERROR_LOAD_LIBRARY 1 //error during LoadLibrary call
#define ERROR_GET_PROC_ADDRESS 2 //error during GetProcAddress
#define ERROR_PARSE_CMD_LINE 3 //error parsing cmd line parameters
#define ERROR_WAIT_FOR_START_SIGNAL 4 //error waiting for a signal to start work
#endif
@@ -0,0 +1,41 @@
/*
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 <Wmistr.h> ///WNODE_HEADER
#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <Evntrace.h> //ETW
#include "Common.h"
BOOL TraceEvents();
TRACEHANDLE StartETWSession(const Profile& profile);
PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession);