Добавлена папка 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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,64 @@
/*
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);
private:
bool _ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch);
bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile);
bool _ParseETWParameter(const char *arg, Profile *pProfile);
bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan);
void _DisplayUsageInfo(const char *pszFilename) const;
bool _GetSizeInBytes(const char *pszSize, UINT64& ullSize) const;
bool _GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath);
// variables that used to be global
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,219 @@
/*
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.
*/
// CmdRequestCreator.cpp : Defines the entry point for the console application.
//
#include "CmdRequestCreator.h"
#include <windows.h>
#include <stdlib.h>
#include <assert.h>
#include "common.h"
#include "errors.h"
#include "..\CmdLineParser\CmdLineParser.h"
#include "..\XmlProfileParser\XmlProfileParser.h"
#include "..\IORequestGenerator\IORequestGenerator.h"
#include "..\ResultParser\ResultParser.h"
#include "..\XmlResultParser\XmlResultParser.h"
/*****************************************************************************/
// global variables
static HANDLE g_hAbortEvent = NULL; // handle to the 'abort' event
// it allows stopping I/O Request Generator in the middle of its work
// the results of its work will be passed to the Results Parser
static HANDLE g_hEventStarted = NULL; // event signalled to notify that the actual (measured) test is to be started
static HANDLE g_hEventFinished = NULL; // event signalled to notify that the actual test has finished
/*****************************************************************************/
// wrapper for printf. printf cannot be used directly, because IORequestGenerator.dll
// may be consumed by gui app which doesn't have stdout
void WINAPI PrintOut(const char *format, va_list args)
{
vprintf(format, args);
}
/*****************************************************************************/
// wrapper for fprintf. fprintf cannot be used directly, because IORequestGenerator.dll
// may be consumed by gui app which doesn't have stdout
void WINAPI PrintError(const char *format, va_list args)
{
vfprintf(stderr, format, args);
}
/*****************************************************************************/
BOOL WINAPI ctrlCRoutine(DWORD dwCtrlType)
{
if( CTRL_C_EVENT == dwCtrlType )
{
printf("\n*** Interrupted by Ctrl-C. Stopping I/O Request Generator. ***\n");
if( !SetEvent(g_hAbortEvent) )
{
fprintf(stderr, "Warning: Setting abort event failed (error code: %u)\n", GetLastError());
}
SetConsoleCtrlHandler(ctrlCRoutine, FALSE);
//indicate that the signal has been handled
return TRUE;
}
else
{
return FALSE;
}
}
/*****************************************************************************/
void TestStarted()
{
if( (NULL != g_hEventStarted) && !SetEvent(g_hEventStarted) )
{
fprintf(stderr, "Warning: Setting test start notification event failed (error code: %u)\n", GetLastError());
}
}
/*****************************************************************************/
void TestFinished()
{
if( (NULL != g_hEventFinished) && !SetEvent(g_hEventFinished) )
{
fprintf(stderr, "Warning: Setting test finish notification event failed (error code: %u)\n", GetLastError());
}
}
DWORD pid = 0;
/*****************************************************************************/
int __cdecl main(int argc, const char* argv[])
{
/// for CrystalDiskMark
int totalScore = 0;
double averageLatency = 0.0;
//
// parse cmd line parameters
//
struct Synchronization synch; //sychronization structure
synch.ulStructSize = sizeof(synch);
synch.hStopEvent = NULL;
synch.hStartEvent = NULL;
CmdLineParser cmdLineParser;
Profile profile;
if (!cmdLineParser.ParseCmdLine(argc, argv, &profile, &synch))
{
return ERROR_PARSE_CMD_LINE;
}
synch.pfnCallbackTestStarted = TestStarted;
synch.pfnCallbackTestFinished = TestFinished;
//
// create abort event if stop event is not explicitly provided by the user (otherwise use the stop event)
//
if (NULL == synch.hStopEvent)
{
synch.hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if( NULL == synch.hStopEvent )
{
fprintf(stderr, "Unable to create an abort event for CTRL+C\n");
//FUTURE EXTENSION: change error code
return 5;
}
}
g_hAbortEvent = synch.hStopEvent; // set abort event to either stop event provided by user or the just created event
//
// capture ctrl+c
//
if( !SetConsoleCtrlHandler(ctrlCRoutine, TRUE) )
{
fprintf(stderr, "Unable to set CTRL+C routine\n");
//FUTURE EXTENSION: change error code
return 6;
}
//
// call IO request generator
//
ResultParser resultParser;
XmlResultParser xmlResultParser;
IResultParser *pResultParser = nullptr;
if (profile.GetResultsFormat() == ResultsFormat::Xml)
{
pResultParser = &xmlResultParser;
}
else
{
pResultParser = &resultParser;
}
IORequestGenerator ioGenerator;
if (!ioGenerator.GenerateRequests(profile, *pResultParser, (PRINTF)PrintOut, (PRINTF)PrintError, (PRINTF)PrintOut, &synch, &totalScore, &averageLatency))
{
fprintf(stderr, "Error generating I/O requests\n");
return 7;
}
if( NULL != synch.hStartEvent )
{
CloseHandle(synch.hStartEvent);
}
if( NULL != synch.hStopEvent )
{
CloseHandle(synch.hStopEvent);
}
if( g_hEventStarted )
{
CloseHandle(g_hEventStarted);
}
if( NULL != g_hEventFinished )
{
CloseHandle(g_hEventFinished);
}
/// for CrystalDiskMark
CHAR name[32];
snprintf(name, 32, "CrystalDiskMark%08X", pid);
auto size = 8;
HANDLE hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, NULL, size, name);
if (hSharedMemory != NULL)
{
auto pMemory = (double*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size);
if (pMemory != NULL)
{
*pMemory = averageLatency;
UnmapViewOfFile(pMemory);
CloseHandle(hSharedMemory);
}
}
// fprintf(stderr, "%f", averageLatency);
return totalScore;
}
@@ -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>
@@ -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,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;
}
@@ -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;
};
@@ -0,0 +1,273 @@
/*
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>
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
template<typename T>
class Histogram
{
private:
unsigned _samples;
#define USE_HASH_TABLE
#ifdef USE_HASH_TABLE
std::unordered_map<T,unsigned> _data;
std::map<T,unsigned> _GetSortedData() const
{
return std::map<T,unsigned>(_data.begin(), _data.end());
}
#else
std::map<T,unsigned> _data;
std::map<T,unsigned> _GetSortedData() const
{
return _data;
}
#endif
public:
Histogram()
: _samples(0)
{}
void Clear()
{
_data.clear();
_samples = 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
{
T min(std::numeric_limits<T>::max());
for (auto i : _data)
{
if (i.first < min)
{
min = i.first;
}
}
return min;
}
T GetMax() const
{
T max(std::numeric_limits<T>::min());
for (auto i : _data)
{
if (i.first > max)
{
max = i.first;
}
}
return max;
}
unsigned GetSampleSize() const
{
return _samples;
}
T GetPercentile(double p) const
{
// ISSUE-REVIEW
// What do the 0th and 100th percentile really mean?
if ((p < 0) || (p > 1))
{
throw std::invalid_argument("Percentile must be >= 0 and <= 1");
}
const double target = GetSampleSize() * p;
unsigned cur = 0;
for (auto i : _GetSortedData())
{
cur += i.second;
if (cur >= target)
{
return i.first;
}
}
throw std::runtime_error("Percentile is undefined");
}
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
{
double sum(0);
unsigned samples = GetSampleSize();
for (auto i : _data)
{
double bucket_val =
static_cast<double>(i.first) * i.second / samples;
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 (auto i : _data)
{
double dev = static_cast<double>(i.first) - mean;
double sqdev = dev*dev;
ssd += i.second * sqdev;
}
return sqrt(ssd / GetSampleSize());
}
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
{
// 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);
std::map<T,unsigned> sortedData = _GetSortedData();
auto pos = sortedData.begin();
unsigned cumulative = 0;
for (unsigned bin = 1; bin <= bins; ++bin)
{
unsigned count = 0;
limit += binSize;
while (pos != sortedData.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
{
std::ostringstream os;
os.precision(std::numeric_limits<T>::digits10);
for (auto i : _GetSortedData())
{
os << i.first << "," << i.second << std::endl;
}
return os.str();
}
std::string GetRaw() const
{
std::ostringstream os;
for (auto i : _GetSortedData())
{
os << i.second << " " << i.first << std::endl;
}
return os.str();
}
};
#pragma pop_macro("min")
#pragma pop_macro("max")
@@ -0,0 +1,143 @@
/*
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"
const unsigned __int64 INVALID_BUCKET_DURATION = 0;
IoBucketizer::IoBucketizer()
: _bucketDuration(INVALID_BUCKET_DURATION),
_validBuckets(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.reserve(_validBuckets);
}
void IoBucketizer::Add(unsigned __int64 ioCompletionTime)
{
if (_bucketDuration == INVALID_BUCKET_DURATION)
{
throw std::runtime_error("IoBucketizer has not been initialized");
}
size_t bucketNumber = static_cast<size_t>(ioCompletionTime / _bucketDuration);
size_t currentSize = _vBuckets.size();
if (currentSize < bucketNumber + 1)
{
_vBuckets.resize(bucketNumber + 1);
// Zero the new entries. Note that size is 1-based and bucketNumber is 0-based.
for (size_t i = currentSize; i <= bucketNumber; i++)
{
_vBuckets[i] = 0;
}
}
_vBuckets[bucketNumber]++;
}
size_t IoBucketizer::GetNumberOfValidBuckets() const
{
// Buckets beyond this may exist since Add is willing to extend the vector
// beyond the expected number of valid buckets, but they are not comparable
// buckets (straggling IOs over the timespan boundary).
return (_vBuckets.size() > _validBuckets ? _validBuckets : _vBuckets.size());
}
size_t IoBucketizer::GetNumberOfBuckets() const
{
return _vBuckets.size();
}
unsigned int IoBucketizer::GetIoBucket(size_t bucketNumber) const
{
return _vBuckets[bucketNumber];
}
double IoBucketizer::_GetMean() const
{
size_t numBuckets = GetNumberOfValidBuckets();
double sum = 0;
for (size_t i = 0; i < numBuckets; i++)
{
sum += static_cast<double>(_vBuckets[i]) / numBuckets;
}
return sum;
}
double IoBucketizer::GetStandardDeviation() const
{
size_t numBuckets = GetNumberOfValidBuckets();
if(numBuckets == 0)
{
return 0.0;
}
double mean = _GetMean();
double ssd = 0;
for (size_t i = 0; i < numBuckets; i++)
{
double dev = static_cast<double>(_vBuckets[i]) - 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());
}
if (other._validBuckets > _validBuckets)
{
_validBuckets = other._validBuckets;
}
for(size_t i = 0; i < other._vBuckets.size(); i++)
{
_vBuckets[i] += other.GetIoBucket(i);
}
}
@@ -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.
*/
#pragma once
#include <vector>
class IoBucketizer
{
public:
IoBucketizer();
void Initialize(unsigned __int64 bucketDuration, size_t validBuckets);
size_t GetNumberOfValidBuckets() const;
size_t GetNumberOfBuckets() const;
unsigned int GetIoBucket(size_t bucketNumber) const;
void Add(unsigned __int64 ioCompletionTime);
double GetStandardDeviation() const;
void Merge(const IoBucketizer& other);
private:
double _GetMean() const;
unsigned __int64 _bucketDuration;
size_t _validBuckets;
std::vector<unsigned int> _vBuckets;
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,87 @@
/*
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, ...);
void *ManagedMalloc(size_t size);
namespace UnitTests
{
class IORequestGeneratorUnitTests;
}
class IORequestGenerator
{
public:
IORequestGenerator() :
_hNTDLL(nullptr)
{
}
bool GenerateRequests(Profile& profile, IResultParser& resultParser, PRINTF pPrintOut, PRINTF pPrintError, PRINTF pPrintVerbose, struct Synchronization *pSynch, int *totalScore, double *averageLatency);
static UINT64 GetNextFileOffset(ThreadParameters& tp, size_t targetNum, UINT64 prevOffset);
static UINT64 GetStartingFileOffset(ThreadParameters& tp, size_t targetNum);
static UINT64 GetThreadBaseFileOffset(ThreadParameters& tp, size_t targetNum);
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;
void _DisplayFileSizeVerbose(bool fVerbose, UINT64 fsize) const;
bool _GetActiveGroupsAndProcs() const;
struct ETWSessionInfo _GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const;
bool _GetSystemPerfInfo(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pInfo, UINT32 uCpuCount) 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,79 @@
/*
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 "OverlappedQueue.h"
#include <assert.h>
OverlappedQueue::OverlappedQueue(void) :
_pHead(nullptr),
_pTail(nullptr),
_cItems(0)
{
}
void OverlappedQueue::Add(OVERLAPPED *pOverlapped)
{
pOverlapped->Internal = NULL;
if (_pHead == nullptr)
{
assert(_pTail == nullptr);
_pHead = pOverlapped;
}
else
{
assert(_pTail != nullptr);
_pTail->Internal = (ULONG_PTR)pOverlapped;
}
_pTail = pOverlapped;
_cItems++;
}
bool OverlappedQueue::IsEmpty(void) const
{
return (_pHead == nullptr);
}
OVERLAPPED *OverlappedQueue::Remove(void)
{
assert(!IsEmpty());
OVERLAPPED *pOverlapped = _pHead;
_pHead = (OVERLAPPED *)pOverlapped->Internal;
if (_pHead == nullptr)
{
_pTail = nullptr;
}
_cItems--;
return pOverlapped;
}
size_t OverlappedQueue::GetCount() const
{
return _cItems;
}
@@ -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,123 @@
/*
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 "ThroughputMeter.h"
ThroughputMeter::ThroughputMeter(void) :
_fRunning(false)
{
}
bool ThroughputMeter::IsRunning(void) const
{
return _fRunning;
}
void ThroughputMeter::Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize)
{
// Initialization
_cbCompleted = 0;
_cIO = 0; // number of completed IOs in the current burst
_cbBlockSize = dwBlockSize;
_fThrottle = false;
_cBytesPerMillisecond = 0;
_fThink = false;
_ullDelayUntil = 0;
_thinkTime = 0;
_burstSize = 0;
_fRunning = false;
/// GetTickCount64 -> GetTickCount
_ullStartTimestamp = GetTickCount();
if (0 != cBytesPerMillisecond)
{
_fThrottle = true;
_cBytesPerMillisecond = cBytesPerMillisecond;
_fRunning = true;
}
else if (0 != dwThinkTime)
{
_fThink = true;
_thinkTime = dwThinkTime;
_burstSize = dwBurstSize;
_fRunning = true;
}
}
DWORD ThroughputMeter::GetSleepTime(void) const
{
if (_fThink)
{
/// GetTickCount64 -> GetTickCount
ULONGLONG ullTimestamp = GetTickCount();
if (ullTimestamp < _ullDelayUntil)
{
return (DWORD)(_ullDelayUntil - ullTimestamp);
}
else
{
return (_fThrottle) ? _GetThrottleTime() : 0;
}
}
else
{
if (_fThrottle) // think time has not been specified only check for throttling
{
return _GetThrottleTime();
}
else
{
return 0;
}
}
}
DWORD ThroughputMeter::_GetThrottleTime(void) const
{
/// GetTickCount64 -> GetTickCount
ULONGLONG cbExpected = (GetTickCount() - _ullStartTimestamp) * _cBytesPerMillisecond;
return cbExpected >= (_cbCompleted + _cbBlockSize) ? 0 : 1;
}
void ThroughputMeter::Adjust(size_t cb)
{
_cbCompleted += cb;
_cIO++;
if (_fThink)
{
if (_cIO >= _burstSize)
{
_cIO = 0;
/// GetTickCount64 -> GetTickCount
_ullDelayUntil = GetTickCount() + _thinkTime;
}
}
}
@@ -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,502 @@
/*
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 "etw.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <Wmistr.h> //WNODE_HEADER
#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <Evntrace.h> //ETW
#include "IORequestGenerator.h"
// variables declared in IORequestGenerator.cpp
extern struct ETWEventCounters g_EtwEventCounters;
extern BOOL volatile g_bTracing;
DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */
DiskIoGuid,
0x3d6fa8d4,
0xfe05,
0x11d0,
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
);
DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */
FileIoGuid,
0x90cbdc39,
0x4a3e,
0x11d1,
0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3
);
DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */
ImageLoadGuid,
0x2cb15d1d,
0x5fc1,
0x11d2,
0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18
);
DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */
PageFaultGuid,
0x3d6fa8d3,
0xfe05,
0x11d0,
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
);
DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */
TcpIpGuid,
0x9a280ac0,
0xc8e0,
0x11d1,
0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2
);
DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */
UdpIpGuid,
0xbf3a50c5,
0xa9c9,
0x4988,
0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80
);
DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */
ProcessGuid,
0x3d6fa8d0,
0xfe05,
0x11d0,
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
);
DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */
RegistryGuid,
0xae53722e,
0xc863,
0x11d2,
0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1
);
DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */
ThreadGuid,
0x3d6fa8d1,
0xfe05,
0x11d0,
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
);
/*****************************************************************************/
// consumes events' data
//
BOOL TraceEvents()
{
TRACEHANDLE handles[1];
EVENT_TRACE_LOGFILE logfile;
memset(&logfile, 0, sizeof(EVENT_TRACE_LOGFILE));
logfile.LoggerName = KERNEL_LOGGER_NAME;
logfile.LogFileName = NULL;
logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
logfile.IsKernelTrace = true;
handles[0] = OpenTrace(&logfile);
if( (TRACEHANDLE)INVALID_HANDLE_VALUE == handles[0] )
{
PrintError("ETW ERROR: OpenTrace failed (error code: %d)\n", GetLastError());
return false;
}
else
{
ProcessTrace(handles, 1, 0, 0);
CloseTrace(handles[0]);
}
return true;
}
/*****************************************************************************/
// allocates memory for ETW properties structure
//
PEVENT_TRACE_PROPERTIES allocateEventTraceProperties()
{
PEVENT_TRACE_PROPERTIES pProperties = NULL;
size_t size = 0;
size = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME);
pProperties = (PEVENT_TRACE_PROPERTIES)malloc(size);
if( NULL == pProperties )
{
PrintError("FATAL ERROR: unable to allocate memory (error code: %d)\n", GetLastError());
return NULL;
}
memset(pProperties, 0, size);
pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pProperties->Wnode.BufferSize = (ULONG)size;
pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
strcpy_s((char *)pProperties+pProperties->LoggerNameOffset,
size-pProperties->LoggerNameOffset, KERNEL_LOGGER_NAME);
return pProperties;
}
/*****************************************************************************/
// callback function for disk I/O events
void WINAPI eventDiskIo(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_IO_READ == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullIORead;
}
else if( EVENT_TRACE_TYPE_IO_WRITE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullIOWrite;
}
}
/*****************************************************************************/
// callback function for LoadImage events
//
void WINAPI eventLoadImage(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_LOAD == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullImageLoad;
}
}
/*****************************************************************************/
// callback function for memory events
//
void WINAPI eventPageFault(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_MM_COW == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullMMCopyOnWrite;
}
else if( EVENT_TRACE_TYPE_MM_DZF == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullMMDemandZeroFault;
}
else if( EVENT_TRACE_TYPE_MM_GPF == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullMMGuardPageFault;
}
else if( EVENT_TRACE_TYPE_MM_HPF == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullMMHardPageFault;
}
else if( EVENT_TRACE_TYPE_MM_TF == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullMMTransitionFault;
}
}
/*****************************************************************************/
// callback function for network and TCP/IP events
//
void WINAPI eventTcpIp(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_ACCEPT == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetAccept;
}
else if( EVENT_TRACE_TYPE_CONNECT == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetConnect;
}
else if( EVENT_TRACE_TYPE_DISCONNECT == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetDisconnect;
}
else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetTcpReceive;
}
else if( EVENT_TRACE_TYPE_RECONNECT == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetReconnect;
}
else if( EVENT_TRACE_TYPE_RETRANSMIT == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetRetransmit;
}
else if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetTcpSend;
}
}
/*****************************************************************************/
// callback function for UDP/IP events
//
void WINAPI eventUdpIp(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetUdpSend;
}
else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullNetUdpReceive;
}
}
/*****************************************************************************/
// callback function for thread events
//
void WINAPI eventThread(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullThreadStart;
}
else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullThreadEnd;
}
}
/*****************************************************************************/
// callback function for process events
//
void WINAPI eventProcess(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullProcessStart;
}
else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullProcessEnd;
}
}
/*****************************************************************************/
// callback function for registry events
//
void WINAPI eventRegistry(PEVENT_TRACE pEvent)
{
if( EVENT_TRACE_TYPE_REGCREATE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegCreate;
}
else if( EVENT_TRACE_TYPE_REGDELETE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegDelete;
}
else if( EVENT_TRACE_TYPE_REGDELETEVALUE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegDeleteValue;
}
else if( EVENT_TRACE_TYPE_REGENUMERATEKEY == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegEnumerateKey;
}
else if( EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegEnumerateValueKey;
}
else if( EVENT_TRACE_TYPE_REGFLUSH == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegFlush;
}
// else if( EVENT_TRACE_TYPE_REGKCBDMP == pEvent->Header.Class.Type )
// {
// ++ETWEventCounters.ullRegKcbDmp;
// }
else if( EVENT_TRACE_TYPE_REGOPEN == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegOpen;
}
else if( EVENT_TRACE_TYPE_REGQUERY == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegQuery;
}
else if( EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegQueryMultipleValue;
}
else if( EVENT_TRACE_TYPE_REGQUERYVALUE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegQueryValue;
}
else if( EVENT_TRACE_TYPE_REGSETINFORMATION == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegSetInformation;
}
else if( EVENT_TRACE_TYPE_REGSETVALUE == pEvent->Header.Class.Type )
{
++g_EtwEventCounters.ullRegSetValue;
}
}
/*****************************************************************************/
// starts ETW session and sets callback functions for various groups of events
//
TRACEHANDLE StartETWSession(const Profile& profile)
{
PEVENT_TRACE_PROPERTIES pProperties;
pProperties = allocateEventTraceProperties();
if (nullptr == pProperties)
{
return 0;
}
pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
//use paged memory
if (profile.GetEtwUsePagedMemory())
{
pProperties->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY;
}
//
// event classes
//
if (profile.GetEtwProcess())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_PROCESS;
SetTraceCallback(&ProcessGuid, eventThread);
}
if (profile.GetEtwThread())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_THREAD;
SetTraceCallback(&ThreadGuid, eventThread);
}
if (profile.GetEtwImageLoad())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD;
SetTraceCallback(&ImageLoadGuid, eventLoadImage);
}
if (profile.GetEtwDiskIO())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
SetTraceCallback(&DiskIoGuid, eventDiskIo);
}
if (profile.GetEtwMemoryPageFaults())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS;
SetTraceCallback(&PageFaultGuid, eventPageFault);
}
if (profile.GetEtwMemoryHardFaults())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS;
SetTraceCallback(&PageFaultGuid, eventPageFault);
}
if (profile.GetEtwNetwork())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP;
SetTraceCallback(&TcpIpGuid, eventTcpIp);
SetTraceCallback(&UdpIpGuid, eventUdpIp);
}
if (profile.GetEtwRegistry())
{
pProperties->EnableFlags |= EVENT_TRACE_FLAG_REGISTRY;
SetTraceCallback(&RegistryGuid, eventRegistry);
}
//
// timer
//
if (profile.GetEtwUsePerfTimer())
{
pProperties->Wnode.ClientContext = 1;
}
if (profile.GetEtwUseSystemTimer())
{
pProperties->Wnode.ClientContext = 2;
}
if (profile.GetEtwUseCyclesCounter())
{
pProperties->Wnode.ClientContext = 3;
}
pProperties->Wnode.Guid = SystemTraceControlGuid;
TRACEHANDLE hTraceSession;
ULONG ret = StartTrace(&hTraceSession, KERNEL_LOGGER_NAME, pProperties);
free(pProperties);
if (ERROR_SUCCESS != ret)
{
PrintError("Error starting trace session\n");
return 0;
}
return hTraceSession;
}
/*****************************************************************************/
// stops ETW session
//
PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession)
{
PEVENT_TRACE_PROPERTIES pProperties;
pProperties = allocateEventTraceProperties();
if( NULL == pProperties )
{
return NULL;
}
ULONG ret;
ret = ControlTrace(hTraceSession, NULL, pProperties, EVENT_TRACE_CONTROL_STOP);
if( ERROR_SUCCESS != ret )
{
PrintError("Error stopping trace session\n");
return NULL;
}
//wait
while(g_bTracing)
{
Sleep(10); // TODO: remove active waiting
}
return pProperties;
}
@@ -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\Common.h"
BOOL TraceEvents();
TRACEHANDLE StartETWSession(const Profile& profile);
PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession);
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Microsoft
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.
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Microsoft
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.
@@ -0,0 +1,14 @@
DISKSPD
=======
DISKSPD is a storage load generator / performance test tool from the Windows/Windows Server and Cloud Server Infrastructure Engineering teams. Please see the included documentation (docx and pdf formats).
Compilation is supported with Visual Studio and Visual Studio Express. Use the Visual Studio solution file inside the diskspd_vs2013 directory.
Source code is hosted at the following repo, if you did not clone it directly:
[https://github.com/microsoft/diskspd](https://github.com/microsoft/diskspd "https://github.com/microsoft/diskspd")
A binary release is hosted by Microsoft at the following location:
[http://aka.ms/diskspd](http://aka.ms/diskspd "http://aka.ms/diskspd")
@@ -0,0 +1,848 @@
/*
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.
*/
// ResultParser.cpp : Defines the entry point for the DLL application.
//
#include "ResultParser.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <Winternl.h> //ntdll.dll
#include <Wmistr.h> //WNODE_HEADER
#include <Evntrace.h>
#include <assert.h>
// TODO: refactor to a single function shared with the XmlResultParser
void ResultParser::_Print(const char *format, ...)
{
assert(nullptr != format);
va_list listArg;
va_start(listArg, format);
char buffer[4096] = {};
vsprintf_s(buffer, _countof(buffer), format, listArg);
va_end(listArg);
_sResult += buffer;
}
/*****************************************************************************/
// display file size in a user-friendly form
//
void ResultParser::_DisplayFileSize(UINT64 fsize)
{
if( fsize > (UINT64)10*1024*1024*1024 ) // > 10GB
{
_Print("%uGB", fsize >> 30);
}
else if( fsize > (UINT64)10*1024*1024 ) // > 10MB
{
_Print("%uMB", fsize >> 20);
}
else if( fsize > 10*1024 ) // > 10KB
{
_Print("%uKB", fsize >> 10);
}
else
{
_Print("%I64uB", fsize);
}
}
/*****************************************************************************/
void ResultParser::_DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo)
{
_Print("\n\n");
_Print(" ETW Buffer Settings & Statistics\n");
_Print("--------------------------------------------------------\n");
_Print("(KB) Buffers (Secs) (Mins)\n");
_Print("Size | Min | Max | Free | Written | Flush Age\n");
_Print("%-5lu %5lu %-5lu %-2lu %8lu %8lu %8d\n\n",
sessionInfo.ulBufferSize,
sessionInfo.ulMinimumBuffers,
sessionInfo.ulMaximumBuffers,
sessionInfo.ulFreeBuffers,
sessionInfo.ulBuffersWritten,
sessionInfo.ulFlushTimer,
sessionInfo.lAgeLimit);
_Print("Allocated Buffers: %lu\n",
sessionInfo.ulNumberOfBuffers);
_Print("LOST EVENTS:%15lu\n",
sessionInfo.ulEventsLost);
_Print("LOST LOG BUFFERS:%10lu\n",
sessionInfo.ulLogBuffersLost);
_Print("LOST REAL TIME BUFFERS:%4lu\n",
sessionInfo.ulRealTimeBuffersLost);
}
/*****************************************************************************/
void ResultParser::_DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters)
{
_Print("\n\n\nETW:\n");
_Print("----\n\n");
if (ETWMask.bDiskIO)
{
_Print("\tDisk I/O\n");
_Print("\t\tRead: %I64u\n", EtwEventCounters.ullIORead);
_Print("\t\tWrite: %I64u\n", EtwEventCounters.ullIOWrite);
}
if (ETWMask.bImageLoad)
{
_Print("\tLoad Image\n");
_Print("\t\tLoad Image: %I64u\n", EtwEventCounters.ullImageLoad);
}
if (ETWMask.bMemoryPageFaults)
{
_Print("\tMemory Page Faults\n");
_Print("\t\tCopy on Write: %I64u\n", EtwEventCounters.ullMMCopyOnWrite);
_Print("\t\tDemand Zero fault: %I64u\n", EtwEventCounters.ullMMDemandZeroFault);
_Print("\t\tGuard Page fault: %I64u\n", EtwEventCounters.ullMMGuardPageFault);
_Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault);
_Print("\t\tTransition fault: %I64u\n", EtwEventCounters.ullMMTransitionFault);
}
if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults )
{
_Print("\tMemory Hard Faults\n");
_Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault);
}
if (ETWMask.bNetwork)
{
_Print("\tNetwork\n");
_Print("\t\tAccept: %I64u\n", EtwEventCounters.ullNetAccept);
_Print("\t\tConnect: %I64u\n", EtwEventCounters.ullNetConnect);
_Print("\t\tDisconnect: %I64u\n", EtwEventCounters.ullNetDisconnect);
_Print("\t\tReconnect: %I64u\n", EtwEventCounters.ullNetReconnect);
_Print("\t\tRetransmit: %I64u\n", EtwEventCounters.ullNetRetransmit);
_Print("\t\tTCP/IP Send: %I64u\n", EtwEventCounters.ullNetTcpSend);
_Print("\t\tTCP/IP Receive: %I64u\n", EtwEventCounters.ullNetTcpReceive);
_Print("\t\tUDP/IP Send: %I64u\n", EtwEventCounters.ullNetUdpSend);
_Print("\t\tUDP/IP Receive: %I64u\n", EtwEventCounters.ullNetUdpReceive);
}
if (ETWMask.bProcess)
{
_Print("\tProcess\n");
_Print("\t\tStart: %I64u\n", EtwEventCounters.ullProcessStart);
_Print("\t\tEnd: %I64u\n", EtwEventCounters.ullProcessEnd);
}
if (ETWMask.bRegistry)
{
_Print("\tRegistry\n");
_Print("\t\tNtCreateKey: %I64u\n",
EtwEventCounters.ullRegCreate);
_Print("\t\tNtDeleteKey: %I64u\n",
EtwEventCounters.ullRegDelete);
_Print("\t\tNtDeleteValueKey: %I64u\n",
EtwEventCounters.ullRegDeleteValue);
_Print("\t\tNtEnumerateKey: %I64u\n",
EtwEventCounters.ullRegEnumerateKey);
_Print("\t\tNtEnumerateValueKey: %I64u\n",
EtwEventCounters.ullRegEnumerateValueKey);
_Print("\t\tNtFlushKey: %I64u\n",
EtwEventCounters.ullRegFlush);
_Print("\t\tKcbDump/create: %I64u\n",
EtwEventCounters.ullRegKcbDmp);
_Print("\t\tNtOpenKey: %I64u\n",
EtwEventCounters.ullRegOpen);
_Print("\t\tNtQueryKey: %I64u\n",
EtwEventCounters.ullRegQuery);
_Print("\t\tNtQueryMultipleValueKey: %I64u\n",
EtwEventCounters.ullRegQueryMultipleValue);
_Print("\t\tNtQueryValueKey: %I64u\n",
EtwEventCounters.ullRegQueryValue);
_Print("\t\tNtSetInformationKey: %I64u\n",
EtwEventCounters.ullRegSetInformation);
_Print("\t\tNtSetValueKey: %I64u\n",
EtwEventCounters.ullRegSetValue);
}
if (ETWMask.bThread)
{
_Print("\tThread\n");
_Print("\t\tStart: %I64u\n", EtwEventCounters.ullThreadStart);
_Print("\t\tEnd: %I64u\n", EtwEventCounters.ullThreadEnd);
}
}
void ResultParser::_PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fCompletionRoutines)
{
_Print("\tpath: '%s'\n", target.GetPath().c_str());
_Print("\t\tthink time: %ums\n", target.GetThinkTime());
_Print("\t\tburst size: %u\n", target.GetBurstSize());
// TODO: completion routines/ports
if (target.GetDisableAllCache())
{
_Print("\t\tsoftware and hardware write cache disabled\n");
}
else if (target.GetDisableOSCache())
{
_Print("\t\tsoftware cache disabled\n");
}
if (!target.GetDisableAllCache() && !target.GetDisableOSCache())
{
_Print("\t\tusing software and hardware write cache\n");
}
if (target.GetZeroWriteBuffers())
{
_Print("\t\tzeroing write buffers\n");
}
if (target.GetRandomDataWriteBufferSize() > 0)
{
_Print("\t\twrite buffer size: %I64u\n", target.GetRandomDataWriteBufferSize());
string sWriteBufferSourcePath = target.GetRandomDataWriteBufferSourcePath();
if (sWriteBufferSourcePath != "")
{
_Print("\t\twrite buffer source: '%s'\n", sWriteBufferSourcePath.c_str());
}
}
if (target.GetUseParallelAsyncIO())
{
_Print("\t\tusing parallel async I/O\n");
}
if (target.GetWriteRatio() == 0)
{
_Print("\t\tperforming read test\n");
}
else if (target.GetWriteRatio() == 100)
{
_Print("\t\tperforming write test\n");
}
else
{
_Print("\t\tperforming mix test (write/read ratio: %d/100)\n", target.GetWriteRatio());
}
_Print("\t\tblock size: %d\n", target.GetBlockSizeInBytes());
if (target.GetUseRandomAccessPattern())
{
_Print("\t\tusing random I/O (alignment: ");
}
else
{
if (target.GetUseInterlockedSequential())
{
_Print("\t\tusing interlocked sequential I/O (stride: ");
}
else
{
_Print("\t\tusing sequential I/O (stride: ");
}
}
_Print("%I64u)\n", target.GetBlockAlignmentInBytes());
_Print("\t\tnumber of outstanding I/O operations: %d\n", target.GetRequestCount());
if (0 != target.GetBaseFileOffsetInBytes())
{
_Print("\t\tbase file offset: %I64u\n", target.GetBaseFileOffsetInBytes());
}
if (0 != target.GetMaxFileSize())
{
_Print("\t\tmax file size: %I64u\n", target.GetMaxFileSize());
}
_Print("\t\tthread stride size: %I64u\n", target.GetThreadStrideInBytes());
if (target.GetSequentialScanHint())
{
_Print("\t\tusing FILE_FLAG_SEQUENTIAL_SCAN hint\n");
}
if (target.GetRandomAccessHint())
{
_Print("\t\tusing FILE_FLAG_RANDOM_ACCESS hint\n");
}
if (fUseThreadsPerFile)
{
_Print("\t\tthreads per file: %d\n", target.GetThreadsPerFile());
}
if (target.GetRequestCount() > 1 && fUseThreadsPerFile)
{
if (fCompletionRoutines)
{
_Print("\t\tusing completion routines (ReadFileEx/WriteFileEx)\n");
}
else
{
_Print("\t\tusing I/O Completion Ports\n");
}
}
if (target.GetIOPriorityHint() == IoPriorityHintVeryLow)
{
_Print("\t\tIO priority: very low\n");
}
else if (target.GetIOPriorityHint() == IoPriorityHintLow)
{
_Print("\t\tIO priority: low\n");
}
else if (target.GetIOPriorityHint() == IoPriorityHintNormal)
{
_Print("\t\tIO priority: normal\n");
}
else
{
_Print("\t\tIO priority: unknown\n");
}
}
void ResultParser::_PrintTimeSpan(const TimeSpan& timeSpan)
{
_Print("\tduration: %us\n", timeSpan.GetDuration());
_Print("\twarm up time: %us\n", timeSpan.GetWarmup());
_Print("\tcool down time: %us\n", timeSpan.GetCooldown());
if (timeSpan.GetDisableAffinity())
{
_Print("\taffinity disabled\n");
}
if (timeSpan.GetMeasureLatency())
{
_Print("\tmeasuring latency\n");
}
if (timeSpan.GetCalculateIopsStdDev())
{
_Print("\tcalculating IOPS stddev with bucket duration = %u milliseconds\n", timeSpan.GetIoBucketDurationInMilliseconds());
}
_Print("\trandom seed: %u\n", timeSpan.GetRandSeed());
vector<UINT32> vAffinity = timeSpan.GetAffinityAssignments();
if ( vAffinity.size() > 0)
{
_Print("\tadvanced affinity: ");
for (unsigned int x = 0; x < vAffinity.size(); ++x)
{
_Print("%d", vAffinity[x]);
if (x < vAffinity.size() - 1)
{
_Print(", ");
}
}
_Print("\n");
}
vector<Target> vTargets(timeSpan.GetTargets());
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
{
_PrintTarget(*i, (timeSpan.GetThreadCount() == 0), timeSpan.GetCompletionRoutines());
}
}
void ResultParser::_PrintProfile(const Profile& profile)
{
_Print("\nCommand Line: %s\n", profile.GetCmdLine().c_str());
_Print("\n");
_Print("Input parameters:\n\n");
if (profile.GetVerbose())
{
_Print("\tusing verbose mode\n");
}
const vector<TimeSpan>& vTimeSpans = profile.GetTimeSpans();
int c = 1;
for (auto i = vTimeSpans.begin(); i != vTimeSpans.end(); i++)
{
_Print("\ttimespan: %3d\n", c++);
_Print("\t-------------\n");
_PrintTimeSpan(*i);
_Print("\n");
}
}
void ResultParser::_PrintCpuUtilization(const Results& results)
{
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount);
char szFloatBuffer[1024];
_Print("\nCPU | Usage | User | Kernel | Idle\n");
_Print("-------------------------------------------\n");
double busyTime = 0;
double totalIdleTime = 0;
double totalUserTime = 0;
double totalKrnlTime = 0;
for (unsigned int x = 0; x<ulProcCount; ++x)
{
double idleTime;
double userTime;
double krnlTime;
double thisTime;
idleTime = 100.0 * results.vSystemProcessorPerfInfo[x].IdleTime.QuadPart / 10000000 / fTime;
krnlTime = 100.0 * results.vSystemProcessorPerfInfo[x].KernelTime.QuadPart / 10000000 / fTime;
userTime = 100.0 * results.vSystemProcessorPerfInfo[x].UserTime.QuadPart / 10000000 / fTime;
thisTime = (krnlTime + userTime) - idleTime;
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "%4u| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
x,
thisTime,
userTime,
krnlTime - idleTime,
idleTime);
_Print("%s", szFloatBuffer);
busyTime += thisTime;
totalIdleTime += idleTime;
totalUserTime += userTime;
totalKrnlTime += krnlTime;
}
_Print("-------------------------------------------\n");
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "avg.| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
busyTime / ulProcCount,
totalUserTime / ulProcCount,
(totalKrnlTime - totalIdleTime) / ulProcCount,
totalIdleTime / ulProcCount);
_Print("%s", szFloatBuffer);
}
void ResultParser::_PrintSectionFieldNames(const TimeSpan& timeSpan)
{
_Print("thread | bytes | I/Os | MB/s | I/O per s %s%s%s| file\n",
timeSpan.GetMeasureLatency() ? "| AvgLat " : "",
timeSpan.GetCalculateIopsStdDev() ? "| IopsStdDev " : "",
timeSpan.GetMeasureLatency() ? "| LatStdDev " : "");
}
void ResultParser::_PrintSectionBorderLine(const TimeSpan& timeSpan)
{
_Print("------------------------------------------------------------------%s%s%s------------\n",
timeSpan.GetMeasureLatency() ? "-----------" : "" ,
timeSpan.GetCalculateIopsStdDev() ? "-------------" : "",
timeSpan.GetMeasureLatency() ? "------------" : "");
}
void ResultParser::_PrintSection(_SectionEnum section, const TimeSpan& timeSpan, const Results& results)
{
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount);
double fBucketTime = timeSpan.GetIoBucketDurationInMilliseconds() / 1000.0;
UINT64 ullTotalBytesCount = 0;
UINT64 ullTotalIOCount = 0;
Histogram<float> totalLatencyHistogram;
IoBucketizer totalIoBucketizer;
_PrintSectionFieldNames(timeSpan);
_PrintSectionBorderLine(timeSpan);
for (unsigned int iThread = 0; iThread < results.vThreadResults.size(); ++iThread)
{
const ThreadResults& threadResults = results.vThreadResults[iThread];
for (unsigned int iFile = 0; iFile < threadResults.vTargetResults.size(); iFile++)
{
const TargetResults& targetResults = threadResults.vTargetResults[iFile];
UINT64 ullBytesCount = 0;
UINT64 ullIOCount = 0;
Histogram<float> latencyHistogram;
IoBucketizer ioBucketizer;
if ((section == _SectionEnum::WRITE) || (section == _SectionEnum::TOTAL))
{
ullBytesCount += targetResults.ullWriteBytesCount;
ullIOCount += targetResults.ullWriteIOCount;
if (timeSpan.GetMeasureLatency())
{
latencyHistogram.Merge(targetResults.writeLatencyHistogram);
totalLatencyHistogram.Merge(targetResults.writeLatencyHistogram);
}
if (timeSpan.GetCalculateIopsStdDev())
{
ioBucketizer.Merge(targetResults.writeBucketizer);
totalIoBucketizer.Merge(targetResults.writeBucketizer);
}
}
if ((section == _SectionEnum::READ) || (section == _SectionEnum::TOTAL))
{
ullBytesCount += targetResults.ullReadBytesCount;
ullIOCount += targetResults.ullReadIOCount;
if (timeSpan.GetMeasureLatency())
{
latencyHistogram.Merge(targetResults.readLatencyHistogram);
totalLatencyHistogram.Merge(targetResults.readLatencyHistogram);
}
if (timeSpan.GetCalculateIopsStdDev())
{
ioBucketizer.Merge(targetResults.readBucketizer);
totalIoBucketizer.Merge(targetResults.readBucketizer);
}
}
_Print("%6u | %15llu | %12llu | %10.2f | %10.2f",
iThread,
ullBytesCount,
ullIOCount,
(double) ullBytesCount / 1024 / 1024 / fTime,
(double) ullIOCount / fTime);
if (timeSpan.GetMeasureLatency())
{
double avgLat = latencyHistogram.GetAvg() / 1000;
_Print(" | %8.3f", avgLat);
}
if (timeSpan.GetCalculateIopsStdDev())
{
double iopsStdDev = ioBucketizer.GetStandardDeviation() / fBucketTime;
_Print(" | %10.2f", iopsStdDev);
}
if (timeSpan.GetMeasureLatency())
{
if (latencyHistogram.GetSampleSize() > 0)
{
double latStdDev = latencyHistogram.GetStandardDeviation() / 1000;
_Print(" | %8.3f", latStdDev);
}
else
{
_Print(" | N/A");
}
}
_Print(" | %s (", targetResults.sPath.c_str());
_DisplayFileSize(targetResults.ullFileSize);
_Print(")\n");
ullTotalBytesCount += ullBytesCount;
ullTotalIOCount += ullIOCount;
}
}
_PrintSectionBorderLine(timeSpan);
double totalAvgLat = 0;
if (timeSpan.GetMeasureLatency())
{
totalAvgLat = totalLatencyHistogram.GetAvg() / 1000;
}
_Print("total: %15llu | %12llu | %10.2f | %10.2f",
ullTotalBytesCount,
ullTotalIOCount,
(double) ullTotalBytesCount / 1024 / 1024 / fTime,
(double) ullTotalIOCount / fTime);
if (section == _SectionEnum::TOTAL)
{
_totalScore = (int)(ullTotalBytesCount / 1000 / fTime);
}
if (timeSpan.GetMeasureLatency())
{
_Print(" | %8.3f", totalAvgLat);
if (section == _SectionEnum::TOTAL)
{
_averageLatency = totalAvgLat;
}
}
if (timeSpan.GetCalculateIopsStdDev())
{
double iopsStdDev = totalIoBucketizer.GetStandardDeviation() / fBucketTime;
_Print(" | %10.2f", iopsStdDev);
}
if (timeSpan.GetMeasureLatency())
{
if (totalLatencyHistogram.GetSampleSize() > 0)
{
double latStdDev = totalLatencyHistogram.GetStandardDeviation() / 1000;
_Print(" | %8.3f", latStdDev);
}
else
{
_Print(" | N/A");
}
}
_Print("\n");
}
void ResultParser::_PrintLatencyPercentiles(const Results& results)
{
Histogram<float> readLatencyHistogram;
Histogram<float> writeLatencyHistogram;
Histogram<float> totalLatencyHistogram;
for (const auto& thread : results.vThreadResults)
{
for (const auto& target : thread.vTargetResults)
{
readLatencyHistogram.Merge(target.readLatencyHistogram);
writeLatencyHistogram.Merge(target.writeLatencyHistogram);
totalLatencyHistogram.Merge(target.writeLatencyHistogram);
totalLatencyHistogram.Merge(target.readLatencyHistogram);
}
}
bool fHasReads = readLatencyHistogram.GetSampleSize() > 0;
bool fHasWrites = writeLatencyHistogram.GetSampleSize() > 0;
_Print(" %%-ile | Read (ms) | Write (ms) | Total (ms)\n");
_Print("----------------------------------------------\n");
string readMin =
fHasReads ?
Util::DoubleToStringHelper(readLatencyHistogram.GetMin()/1000) :
"N/A";
string writeMin =
fHasWrites ?
Util::DoubleToStringHelper(writeLatencyHistogram.GetMin() / 1000) :
"N/A";
_Print(" min | %10s | %10s | %10.3lf\n",
readMin.c_str(), writeMin.c_str(), totalLatencyHistogram.GetMin()/1000);
PercentileDescriptor percentiles[] =
{
{ 0.25, "25th" },
{ 0.50, "50th" },
{ 0.75, "75th" },
{ 0.90, "90th" },
{ 0.95, "95th" },
{ 0.99, "99th" },
{ 0.999, "3-nines" },
{ 0.9999, "4-nines" },
{ 0.99999, "5-nines" },
{ 0.999999, "6-nines" },
{ 0.9999999, "7-nines" },
{ 0.99999999, "8-nines" },
};
for (auto p : percentiles)
{
string readPercentile =
fHasReads ?
Util::DoubleToStringHelper(readLatencyHistogram.GetPercentile(p.Percentile) / 1000) :
"N/A";
string writePercentile =
fHasWrites ?
Util::DoubleToStringHelper(writeLatencyHistogram.GetPercentile(p.Percentile) / 1000) :
"N/A";
_Print("%7s | %10s | %10s | %10.3lf\n",
p.Name.c_str(),
readPercentile.c_str(),
writePercentile.c_str(),
totalLatencyHistogram.GetPercentile(p.Percentile)/1000);
}
string readMax = Util::DoubleToStringHelper(readLatencyHistogram.GetMax() / 1000);
string writeMax = Util::DoubleToStringHelper(writeLatencyHistogram.GetMax() / 1000);
_Print(" max | %10s | %10s | %10.3lf\n",
fHasReads ? readMax.c_str() : "N/A",
fHasWrites ? writeMax.c_str() : "N/A",
totalLatencyHistogram.GetMax()/1000);
}
int ResultParser::GetTotalScore()
{
return _totalScore;
}
double ResultParser::GetAverageLatency()
{
return _averageLatency;
}
string ResultParser::ParseResults(Profile& profile, const SystemInformation& system, vector<Results> vResults)
{
// TODO: print text representation of system information (see xml parser)
UNREFERENCED_PARAMETER(system);
_sResult.clear();
_PrintProfile(profile);
for (size_t iResult = 0; iResult < vResults.size(); iResult++)
{
_Print("\n\nResults for timespan %d:\n", iResult + 1);
_Print("*******************************************************************************\n");
const Results& results = vResults[iResult];
const TimeSpan& timeSpan = profile.GetTimeSpans()[iResult];
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration
char szFloatBuffer[1024];
// There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file.
// In the latter case vThreadResults.size() == number of threads per file * file count
size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size();
if (fTime < 0.0000001)
{
_Print("The test was interrupted before the measurements began. No results are displayed.\n");
}
else
{
// TODO: parameters.bCreateFile;
_Print("\n");
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "actual test time:\t%.2lfs\n", fTime);
_Print("%s", szFloatBuffer);
_Print("thread count:\t\t%u\n", ulThreadCnt);
_Print("proc count:\t\t%u\n", ulProcCount);
_PrintCpuUtilization(results);
_Print("\nTotal IO\n");
_PrintSection(_SectionEnum::TOTAL, timeSpan, results);
_Print("\nRead IO\n");
_PrintSection(_SectionEnum::READ, timeSpan, results);
_Print("\nWrite IO\n");
_PrintSection(_SectionEnum::WRITE, timeSpan, results);
if (timeSpan.GetMeasureLatency())
{
_Print("\n\n");
_PrintLatencyPercentiles(results);
}
//etw
if (results.fUseETW)
{
_DisplayETW(results.EtwMask, results.EtwEventCounters);
_DisplayETWSessionInfo(results.EtwSessionInfo);
}
}
}
if (vResults.size() > 1)
{
_Print("\n\nTotals:\n");
_Print("*******************************************************************************\n\n");
_Print("type | bytes | I/Os | MB/s | I/O per s\n");
_Print("-------------------------------------------------------------------------------\n");
UINT64 cbTotalWritten = 0;
UINT64 cbTotalRead = 0;
UINT64 cTotalWriteIO = 0;
UINT64 cTotalReadIO = 0;
UINT64 cTotalTicks = 0;
for (auto pResults = vResults.begin(); pResults != vResults.end(); pResults++)
{
double time = PerfTimer::PerfTimeToSeconds(pResults->ullTimeCount);
if (time >= 0.0000001) // skip timespans that were interrupted
{
cTotalTicks += pResults->ullTimeCount;
auto vThreadResults = pResults->vThreadResults;
for (auto pThreadResults = vThreadResults.begin(); pThreadResults != vThreadResults.end(); pThreadResults++)
{
for (auto pTargetResults = pThreadResults->vTargetResults.begin(); pTargetResults != pThreadResults->vTargetResults.end(); pTargetResults++)
{
cbTotalRead += pTargetResults->ullReadBytesCount;
cbTotalWritten += pTargetResults->ullWriteBytesCount;
cTotalReadIO += pTargetResults->ullReadIOCount;
cTotalWriteIO += pTargetResults->ullWriteIOCount;
}
}
}
}
double totalTime = PerfTimer::PerfTimeToSeconds(cTotalTicks);
_Print("write | %15I64u | %12I64u | %10.2lf | %10.2lf\n",
cbTotalWritten,
cTotalWriteIO,
(double)cbTotalWritten / 1024 / 1024 / totalTime,
(double)cTotalWriteIO / totalTime);
_Print("read | %15I64u | %12I64u | %10.2lf | %10.2lf\n",
cbTotalRead,
cTotalReadIO,
(double)cbTotalRead / 1024 / 1024 / totalTime,
(double)cTotalReadIO / totalTime);
_Print("-------------------------------------------------------------------------------\n");
_Print("total | %15I64u | %12I64u | %10.2lf | %10.2lf\n\n",
cbTotalRead + cbTotalWritten,
cTotalReadIO + cTotalWriteIO,
(double)(cbTotalRead + cbTotalWritten) / 1024 / 1024 / totalTime,
(double)(cTotalReadIO + cTotalWriteIO) / totalTime);
_Print("total test time:\t%.2lfs\n", totalTime);
}
return _sResult;
}
@@ -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 "Common.h"
namespace UnitTests
{
class ResultParserUnitTests;
}
class ResultParser : public IResultParser
{
public:
string ParseResults(Profile& profile, const SystemInformation& system, vector<Results> vResults);
int GetTotalScore();
double GetAverageLatency();
private:
void _DisplayFileSize(UINT64 fsize);
void _DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo);
void _DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters);
void _Print(const char *format, ...);
void _PrintProfile(const Profile& profile);
void _PrintCpuUtilization(const Results&);
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 _PrintTimeSpan(const TimeSpan &timeSpan);
void _PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fCompletionRoutines);
string _sResult;
int _totalScore;
double _averageLatency;
friend class UnitTests::ResultParserUnitTests;
};
@@ -0,0 +1,885 @@
/*
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 "XmlProfileParser.h"
#include <Objbase.h>
#include <msxml6.h>
#include <assert.h>
// the vc com headers define a partial set of smartptr typedefs, which unfortunately
// aren't 1) complete for our use case and 2) vary between revs of the headers.
// this define disables the automatic definitions, letting us do them ourselves.
#define _COM_NO_STANDARD_GUIDS_
#include <comdef.h>
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument2, __uuidof(IXMLDOMDocument2));
_COM_SMARTPTR_TYPEDEF(IXMLDOMNode, __uuidof(IXMLDOMNodeList));
_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList, __uuidof(IXMLDOMNodeList));
bool XmlProfileParser::ParseFile(const char *pszPath, Profile *pProfile)
{
assert(pszPath != nullptr);
assert(pProfile != nullptr);
bool fComInitialized = false;
HRESULT hr = CoInitialize(nullptr);
if (SUCCEEDED(hr))
{
fComInitialized = true;
IXMLDOMDocument2Ptr spXmlDoc;
hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlDoc));
if (SUCCEEDED(hr))
{
hr = spXmlDoc->put_async(VARIANT_FALSE);
if (SUCCEEDED(hr))
{
VARIANT_BOOL fvIsOk;
_variant_t vPath(pszPath);
hr = spXmlDoc->load(vPath, &fvIsOk);
if (SUCCEEDED(hr))
{
bool fVerbose;
hr = _GetVerbose(spXmlDoc, &fVerbose);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetVerbose(fVerbose);
}
if (SUCCEEDED(hr))
{
DWORD dwProgress;
hr = _GetProgress(spXmlDoc, &dwProgress);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetProgress(dwProgress);
}
}
if (SUCCEEDED(hr))
{
string sResultFormat;
hr = _GetString(spXmlDoc, "//Profile/ResultFormat", &sResultFormat);
if (SUCCEEDED(hr) && (hr != S_FALSE) && sResultFormat == "xml")
{
pProfile->SetResultsFormat(ResultsFormat::Xml);
}
}
if (SUCCEEDED(hr))
{
string sCreateFiles;
hr = _GetString(spXmlDoc, "//Profile/PrecreateFiles", &sCreateFiles);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
if (sCreateFiles == "UseMaxSize")
{
pProfile->SetPrecreateFiles(PrecreateFiles::UseMaxSize);
}
else if (sCreateFiles == "CreateOnlyFilesWithConstantSizes")
{
pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes);
}
else if (sCreateFiles == "CreateOnlyFilesWithConstantOrZeroSizes")
{
pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes);
}
else
{
hr = E_INVALIDARG;
}
}
}
if (SUCCEEDED(hr))
{
hr = _ParseEtw(spXmlDoc, pProfile);
}
if (SUCCEEDED(hr))
{
hr = _ParseTimeSpans(spXmlDoc, pProfile);
}
}
}
}
}
if (fComInitialized)
{
CoUninitialize();
}
return SUCCEEDED(hr);
}
HRESULT XmlProfileParser::_ParseEtw(IXMLDOMDocument2 &XmlDoc, Profile *pProfile)
{
bool fEtwProcess;
HRESULT hr = _GetBool(XmlDoc, "//Profile/ETW/Process", &fEtwProcess);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwProcess(fEtwProcess);
}
if (SUCCEEDED(hr))
{
bool fEtwThread;
hr = _GetBool(XmlDoc, "//Profile/ETW/Thread", &fEtwThread);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwThread(fEtwThread);
}
}
if (SUCCEEDED(hr))
{
bool fEtwImageLoad;
hr = _GetBool(XmlDoc, "//Profile/ETW/ImageLoad", &fEtwImageLoad);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwImageLoad(fEtwImageLoad);
}
}
if (SUCCEEDED(hr))
{
bool fEtwDiskIO;
hr = _GetBool(XmlDoc, "//Profile/ETW/DiskIO", &fEtwDiskIO);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwDiskIO(fEtwDiskIO);
}
}
if (SUCCEEDED(hr))
{
bool fEtwMemoryPageFaults;
hr = _GetBool(XmlDoc, "//Profile/ETW/MemoryPageFaults", &fEtwMemoryPageFaults);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwMemoryPageFaults(fEtwMemoryPageFaults);
}
}
if (SUCCEEDED(hr))
{
bool fEtwMemoryHardFaults;
hr = _GetBool(XmlDoc, "//Profile/ETW/MemoryHardFaults", &fEtwMemoryHardFaults);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwMemoryHardFaults(fEtwMemoryHardFaults);
}
}
if (SUCCEEDED(hr))
{
bool fEtwNetwork;
hr = _GetBool(XmlDoc, "//Profile/ETW/Network", &fEtwNetwork);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwNetwork(fEtwNetwork);
}
}
if (SUCCEEDED(hr))
{
bool fEtwRegistry;
hr = _GetBool(XmlDoc, "//Profile/ETW/Registry", &fEtwRegistry);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwRegistry(fEtwRegistry);
}
}
if (SUCCEEDED(hr))
{
bool fEtwUsePagedMemory;
hr = _GetBool(XmlDoc, "//Profile/ETW/UsePagedMemory", &fEtwUsePagedMemory);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwUsePagedMemory(fEtwUsePagedMemory);
}
}
if (SUCCEEDED(hr))
{
bool fEtwUsePerfTimer;
hr = _GetBool(XmlDoc, "//Profile/ETW/UsePerfTimer", &fEtwUsePerfTimer);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwUsePerfTimer(fEtwUsePerfTimer);
}
}
if (SUCCEEDED(hr))
{
bool fEtwUseSystemTimer;
hr = _GetBool(XmlDoc, "//Profile/ETW/UseSystemTimer", &fEtwUseSystemTimer);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwUseSystemTimer(fEtwUseSystemTimer);
}
}
if (SUCCEEDED(hr))
{
bool fEtwUseCyclesCounter;
hr = _GetBool(XmlDoc, "//Profile/ETW/UseCyclesCounter", &fEtwUseCyclesCounter);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetEtwEnabled(true);
pProfile->SetEtwUseCyclesCounter(fEtwUseCyclesCounter);
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseTimeSpans(IXMLDOMDocument2 &XmlDoc, Profile *pProfile)
{
IXMLDOMNodeListPtr spNodeList;
_variant_t query("//Profile/TimeSpans/TimeSpan");
HRESULT hr = XmlDoc.selectNodes(query.bstrVal, &spNodeList);
if (SUCCEEDED(hr))
{
long cNodes;
hr = spNodeList->get_length(&cNodes);
if (SUCCEEDED(hr))
{
for (int i = 0; i < cNodes; i++)
{
IXMLDOMNodePtr spNode;
hr = spNodeList->get_item(i, &spNode);
if (SUCCEEDED(hr))
{
TimeSpan timeSpan;
hr = _ParseTimeSpan(spNode, &timeSpan);
if (SUCCEEDED(hr))
{
pProfile->AddTimeSpan(timeSpan);
}
}
}
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseTimeSpan(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan)
{
UINT32 ulDuration;
HRESULT hr = _GetUINT32(XmlNode, "Duration", &ulDuration);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetDuration(ulDuration);
}
if (SUCCEEDED(hr))
{
UINT32 ulWarmup;
hr = _GetUINT32(XmlNode, "Warmup", &ulWarmup);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetWarmup(ulWarmup);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulCooldown;
hr = _GetUINT32(XmlNode, "Cooldown", &ulCooldown);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetCooldown(ulCooldown);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulRandSeed;
hr = _GetUINT32(XmlNode, "RandSeed", &ulRandSeed);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetRandSeed(ulRandSeed);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulThreadCount;
hr = _GetUINT32(XmlNode, "ThreadCount", &ulThreadCount);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetThreadCount(ulThreadCount);
}
}
if (SUCCEEDED(hr))
{
bool fGroupAffinity;
hr = _GetBool(XmlNode, "GroupAffinity", &fGroupAffinity);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetGroupAffinity(fGroupAffinity);
}
}
if (SUCCEEDED(hr))
{
bool fDisableAffinity;
hr = _GetBool(XmlNode, "DisableAffinity", &fDisableAffinity);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetDisableAffinity(fDisableAffinity);
}
}
if (SUCCEEDED(hr))
{
bool fCompletionRoutines;
hr = _GetBool(XmlNode, "CompletionRoutines", &fCompletionRoutines);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetCompletionRoutines(fCompletionRoutines);
}
}
if (SUCCEEDED(hr))
{
bool fMeasureLatency;
hr = _GetBool(XmlNode, "MeasureLatency", &fMeasureLatency);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetMeasureLatency(fMeasureLatency);
}
}
if (SUCCEEDED(hr))
{
bool fCalculateIopsStdDev;
hr = _GetBool(XmlNode, "CalculateIopsStdDev", &fCalculateIopsStdDev);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetCalculateIopsStdDev(fCalculateIopsStdDev);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulIoBucketDuration;
hr = _GetUINT32(XmlNode, "IoBucketDuration", &ulIoBucketDuration);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTimeSpan->SetIoBucketDurationInMilliseconds(ulIoBucketDuration);
}
}
if (SUCCEEDED(hr))
{
hr = _ParseAffinityAssignment(XmlNode, pTimeSpan);
}
if (SUCCEEDED(hr))
{
hr = _ParseTargets(XmlNode, pTimeSpan);
}
return hr;
}
HRESULT XmlProfileParser::_ParseTargets(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan)
{
_variant_t query("Targets/Target");
IXMLDOMNodeListPtr spNodeList;
HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList);
if (SUCCEEDED(hr))
{
long cNodes;
hr = spNodeList->get_length(&cNodes);
if (SUCCEEDED(hr))
{
for (int i = 0; i < cNodes; i++)
{
IXMLDOMNodePtr spNode;
hr = spNodeList->get_item(i, &spNode);
if (SUCCEEDED(hr))
{
Target target;
_ParseTarget(spNode, &target);
pTimeSpan->AddTarget(target);
}
}
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseRandomDataSource(IXMLDOMNode &XmlNode, Target *pTarget)
{
IXMLDOMNodeListPtr spNodeList;
_variant_t query("RandomDataSource");
HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList);
if (SUCCEEDED(hr))
{
long cNodes;
hr = spNodeList->get_length(&cNodes);
if (SUCCEEDED(hr) && (cNodes == 1))
{
IXMLDOMNodePtr spNode;
hr = spNodeList->get_item(0, &spNode);
if (SUCCEEDED(hr))
{
UINT64 cb;
hr = _GetUINT64(spNode, "SizeInBytes", &cb);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
pTarget->SetRandomDataWriteBufferSize(cb);
string sPath;
hr = _GetString(spNode, "FilePath", &sPath);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
pTarget->SetRandomDataWriteBufferSourcePath(sPath);
}
}
}
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseWriteBufferContent(IXMLDOMNode &XmlNode, Target *pTarget)
{
IXMLDOMNodeListPtr spNodeList;
_variant_t query("WriteBufferContent");
HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList);
if (SUCCEEDED(hr))
{
long cNodes;
hr = spNodeList->get_length(&cNodes);
if (SUCCEEDED(hr) && (cNodes == 1))
{
IXMLDOMNodePtr spNode;
hr = spNodeList->get_item(0, &spNode);
if (SUCCEEDED(hr))
{
string sPattern;
hr = _GetString(spNode, "Pattern", &sPattern);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
if (sPattern == "sequential")
{
// that's the default option - do nothing
}
else if (sPattern == "zero")
{
pTarget->SetZeroWriteBuffers(true);
}
else if (sPattern == "random")
{
hr = _ParseRandomDataSource(spNode, pTarget);
}
else
{
hr = E_INVALIDARG;
}
}
}
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseTarget(IXMLDOMNode &XmlNode, Target *pTarget)
{
string sPath;
HRESULT hr = _GetString(XmlNode, "Path", &sPath);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetPath(sPath);
}
if (SUCCEEDED(hr))
{
DWORD dwBlockSize;
hr = _GetDWORD(XmlNode, "BlockSize", &dwBlockSize);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetBlockSizeInBytes(dwBlockSize);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullStrideSize;
hr = _GetUINT64(XmlNode, "StrideSize", &ullStrideSize);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetBlockAlignmentInBytes(ullStrideSize);
}
}
if (SUCCEEDED(hr))
{
bool fInterlockedSequential;
hr = _GetBool(XmlNode, "InterlockedSequential", &fInterlockedSequential);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetUseInterlockedSequential(fInterlockedSequential);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullBaseFileOffset;
hr = _GetUINT64(XmlNode, "BaseFileOffset", &ullBaseFileOffset);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetBaseFileOffsetInBytes(ullBaseFileOffset);
}
}
if (SUCCEEDED(hr))
{
bool fSequentialScan;
hr = _GetBool(XmlNode, "SequentialScan", &fSequentialScan);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetSequentialScanHint(fSequentialScan);
}
}
if (SUCCEEDED(hr))
{
bool fRandomAccess;
hr = _GetBool(XmlNode, "RandomAccess", &fRandomAccess);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetRandomAccessHint(fRandomAccess);
}
}
if (SUCCEEDED(hr))
{
bool fUseLargePages;
hr = _GetBool(XmlNode, "UseLargePages", &fUseLargePages);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetUseLargePages(fUseLargePages);
}
}
if (SUCCEEDED(hr))
{
DWORD dwRequestCount;
hr = _GetDWORD(XmlNode, "RequestCount", &dwRequestCount);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetRequestCount(dwRequestCount);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullRandom;
hr = _GetUINT64(XmlNode, "Random", &ullRandom);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetUseRandomAccessPattern(true);
pTarget->SetBlockAlignmentInBytes(ullRandom);
}
}
if (SUCCEEDED(hr))
{
bool fDisableOSCache;
hr = _GetBool(XmlNode, "DisableOSCache", &fDisableOSCache);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetDisableOSCache(fDisableOSCache);
}
}
if (SUCCEEDED(hr))
{
bool fDisableAllCache;
hr = _GetBool(XmlNode, "DisableAllCache", &fDisableAllCache);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetDisableAllCache(fDisableAllCache);
}
}
if (SUCCEEDED(hr))
{
hr = _ParseWriteBufferContent(XmlNode, pTarget);
}
if (SUCCEEDED(hr))
{
DWORD dwBurstSize;
hr = _GetDWORD(XmlNode, "BurstSize", &dwBurstSize);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetBurstSize(dwBurstSize);
pTarget->SetUseBurstSize(true);
}
}
if (SUCCEEDED(hr))
{
DWORD dwThinkTime;
hr = _GetDWORD(XmlNode, "ThinkTime", &dwThinkTime);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetThinkTime(dwThinkTime);
pTarget->SetEnableThinkTime(true);
}
}
if (SUCCEEDED(hr))
{
DWORD dwThroughput;
hr = _GetDWORD(XmlNode, "Throughput", &dwThroughput);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetThroughput(dwThroughput);
}
}
if (SUCCEEDED(hr))
{
DWORD dwThreadsPerFile;
hr = _GetDWORD(XmlNode, "ThreadsPerFile", &dwThreadsPerFile);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetThreadsPerFile(dwThreadsPerFile);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullFileSize;
hr = _GetUINT64(XmlNode, "FileSize", &ullFileSize);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetFileSize(ullFileSize);
pTarget->SetCreateFile(true);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullMaxFileSize;
hr = _GetUINT64(XmlNode, "MaxFileSize", &ullMaxFileSize);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetMaxFileSize(ullMaxFileSize);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulWriteRatio;
hr = _GetUINT32(XmlNode, "WriteRatio", &ulWriteRatio);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetWriteRatio(ulWriteRatio);
}
}
if (SUCCEEDED(hr))
{
bool fParallelAsyncIO;
hr = _GetBool(XmlNode, "ParallelAsyncIO", &fParallelAsyncIO);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetUseParallelAsyncIO(fParallelAsyncIO);
}
}
if (SUCCEEDED(hr))
{
UINT64 ullThreadStride;
hr = _GetUINT64(XmlNode, "ThreadStride", &ullThreadStride);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pTarget->SetThreadStrideInBytes(ullThreadStride);
}
}
if (SUCCEEDED(hr))
{
UINT32 ulIOPriority;
hr = _GetUINT32(XmlNode, "IOPriority", &ulIOPriority);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal };
pTarget->SetIOPriorityHint(hint[ulIOPriority - 1]);
}
}
return hr;
}
HRESULT XmlProfileParser::_ParseAffinityAssignment(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan)
{
IXMLDOMNodeListPtr spNodeList;
_variant_t query("Affinity/AffinityAssignment");
HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList);
if (SUCCEEDED(hr))
{
long cNodes;
hr = spNodeList->get_length(&cNodes);
if (SUCCEEDED(hr))
{
for (int i = 0; i < cNodes; i++)
{
IXMLDOMNodePtr spNode;
hr = spNodeList->get_item(i, &spNode);
if (SUCCEEDED(hr))
{
BSTR bstrText;
hr = spNode->get_text(&bstrText);
if (SUCCEEDED(hr))
{
pTimeSpan->AddAffinityAssignment(_wtoi((wchar_t *)bstrText)); // TODO: change to unsigned
SysFreeString(bstrText);
}
}
}
}
}
return hr;
}
HRESULT XmlProfileParser::_GetUINT32(IXMLDOMNode &XmlNode, const char *pszQuery, UINT32 *pulValue) const
{
IXMLDOMNodePtr spNode;
_variant_t query(pszQuery);
HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
BSTR bstrText;
hr = spNode->get_text(&bstrText);
if (SUCCEEDED(hr))
{
*pulValue = _wtoi((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints
SysFreeString(bstrText);
}
}
return hr;
}
HRESULT XmlProfileParser::_GetString(IXMLDOMNode &XmlNode, const char *pszQuery, string *psValue) const
{
IXMLDOMNodePtr spNode;
_variant_t query(pszQuery);
HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
BSTR bstrText;
hr = spNode->get_text(&bstrText);
if (SUCCEEDED(hr))
{
// TODO: use wstring?
char path[MAX_PATH] = {};
WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, (wchar_t *)bstrText, static_cast<int>(wcslen((wchar_t *)bstrText)), path, sizeof(path)-1, 0 /*lpDefaultChar*/, 0 /*lpUsedDefaultChar*/);
*psValue = string(path);
}
SysFreeString(bstrText);
}
return hr;
}
HRESULT XmlProfileParser::_GetUINT64(IXMLDOMNode &XmlNode, const char *pszQuery, UINT64 *pullValue) const
{
IXMLDOMNodePtr spNode;
_variant_t query(pszQuery);
HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
BSTR bstrText;
hr = spNode->get_text(&bstrText);
if (SUCCEEDED(hr))
{
*pullValue = _wtoi64((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints
}
SysFreeString(bstrText);
}
return hr;
}
HRESULT XmlProfileParser::_GetDWORD(IXMLDOMNode &XmlNode, const char *pszQuery, DWORD *pdwValue) const
{
UINT32 value = 0;
HRESULT hr = _GetUINT32(XmlNode, pszQuery, &value);
if (SUCCEEDED(hr))
{
*pdwValue = value;
}
return hr;
}
HRESULT XmlProfileParser::_GetBool(IXMLDOMNode &XmlNode, const char *pszQuery, bool *pfValue) const
{
HRESULT hr = S_OK;
IXMLDOMNodePtr spNode;
_variant_t query(pszQuery);
hr = XmlNode.selectSingleNode(query.bstrVal, &spNode);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
BSTR bstrText;
hr = spNode->get_text(&bstrText);
if (SUCCEEDED(hr))
{
*pfValue = (_wcsicmp(L"true", (wchar_t *)bstrText) == 0);
SysFreeString(bstrText);
}
}
return hr;
}
HRESULT XmlProfileParser::_GetVerbose(IXMLDOMDocument2 &pXmlDoc, bool *pfVerbose)
{
return _GetBool(pXmlDoc, "//Profile/Verbose", pfVerbose);
}
HRESULT XmlProfileParser::_GetProgress(IXMLDOMDocument2 &pXmlDoc, DWORD *pdwProgress)
{
return _GetDWORD(pXmlDoc, "//Profile/Progress", pdwProgress);
}
@@ -0,0 +1,57 @@
/*
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);
private:
HRESULT _ParseEtw(IXMLDOMDocument2 &XmlDoc, Profile *pProfile);
HRESULT _ParseTimeSpans(IXMLDOMDocument2 &XmlDoc, Profile *pProfile);
HRESULT _ParseTimeSpan(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan);
HRESULT _ParseTargets(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan);
HRESULT _ParseRandomDataSource(IXMLDOMNode &XmlNode, Target *pTarget);
HRESULT _ParseWriteBufferContent(IXMLDOMNode &XmlNode, Target *pTarget);
HRESULT _ParseTarget(IXMLDOMNode &XmlNode, Target *pTarget);
HRESULT _ParseAffinityAssignment(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan);
HRESULT _GetString(IXMLDOMNode &XmlNode, const char *pszQuery, string *psValue) const;
HRESULT _GetUINT32(IXMLDOMNode &XmlNode, const char *pszQuery, UINT32 *pulValue) const;
HRESULT _GetUINT64(IXMLDOMNode &XmlNode, const char *pszQuery, UINT64 *pullValue) const;
HRESULT _GetDWORD(IXMLDOMNode &XmlNode, const char *pszQuery, DWORD *pdwValue) const;
HRESULT _GetBool(IXMLDOMNode &XmlNode, const char *pszQuery, bool *pfValue) const;
HRESULT _GetVerbose(IXMLDOMDocument2 &XmlDoc, bool *pfVerbose);
HRESULT _GetProgress(IXMLDOMDocument2 &XmlDoc, DWORD *pdwProgress);
};
@@ -0,0 +1,273 @@
#pragma once
#using <mscorlib.dll>
#using <System.dll>
#using <System.Data.dll>
#using <System.Xml.dll>
using namespace System::Security::Permissions;
[assembly:SecurityPermissionAttribute(SecurityAction::RequestMinimum, SkipVerification=false)];
//
// このソース コードは xsd によって自動生成されました。Version=4.0.30319.33440 です。
//
using namespace System;
ref class NewDataSet;
/// <summary>
///Represents a strongly typed in-memory cache of data.
///</summary>
[System::Serializable,
System::ComponentModel::DesignerCategoryAttribute(L"code"),
System::ComponentModel::ToolboxItem(true),
System::Xml::Serialization::XmlSchemaProviderAttribute(L"GetTypedDataSetSchema"),
System::Xml::Serialization::XmlRootAttribute(L"NewDataSet"),
System::ComponentModel::Design::HelpKeywordAttribute(L"vs.data.DataSet")]
public ref class NewDataSet : public ::System::Data::DataSet {
private: ::System::Data::SchemaSerializationMode _schemaSerializationMode;
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
NewDataSet();
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context);
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::BrowsableAttribute(true),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Visible)]
virtual property ::System::Data::SchemaSerializationMode SchemaSerializationMode {
::System::Data::SchemaSerializationMode get() override;
System::Void set(::System::Data::SchemaSerializationMode value) override;
}
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)]
property ::System::Data::DataTableCollection^ Tables {
::System::Data::DataTableCollection^ get() new;
}
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)]
property ::System::Data::DataRelationCollection^ Relations {
::System::Data::DataRelationCollection^ get() new;
}
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Void InitializeDerivedDataSet() override;
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Data::DataSet^ Clone() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Boolean ShouldSerializeTables() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Boolean ShouldSerializeRelations() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Void ReadXmlSerializable(::System::Xml::XmlReader^ reader) override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Xml::Schema::XmlSchema^ GetSchemaSerializable() override;
internal: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitVars();
internal: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitVars(::System::Boolean initTable);
private: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitClass();
private: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e);
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
static ::System::Xml::Schema::XmlSchemaComplexType^ GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs);
};
inline NewDataSet::NewDataSet() {
this->BeginInit();
this->InitClass();
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged);
__super::Tables->CollectionChanged += schemaChangedHandler;
__super::Relations->CollectionChanged += schemaChangedHandler;
this->EndInit();
}
inline NewDataSet::NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context) :
::System::Data::DataSet(info, context, false) {
if (this->IsBinarySerialized(info, context) == true) {
this->InitVars(false);
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler1 = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged);
this->Tables->CollectionChanged += schemaChangedHandler1;
this->Relations->CollectionChanged += schemaChangedHandler1;
return;
}
::System::String^ strSchema = (cli::safe_cast<::System::String^ >(info->GetValue(L"XmlSchema", ::System::String::typeid)));
if (this->DetermineSchemaSerializationMode(info, context) == ::System::Data::SchemaSerializationMode::IncludeSchema) {
::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet());
ds->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema)))));
this->DataSetName = ds->DataSetName;
this->Prefix = ds->Prefix;
this->Namespace = ds->Namespace;
this->Locale = ds->Locale;
this->CaseSensitive = ds->CaseSensitive;
this->EnforceConstraints = ds->EnforceConstraints;
this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add);
this->InitVars();
}
else {
this->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema)))));
}
this->GetSerializationData(info, context);
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged);
__super::Tables->CollectionChanged += schemaChangedHandler;
this->Relations->CollectionChanged += schemaChangedHandler;
}
inline ::System::Data::SchemaSerializationMode NewDataSet::SchemaSerializationMode::get() {
return this->_schemaSerializationMode;
}
inline System::Void NewDataSet::SchemaSerializationMode::set(::System::Data::SchemaSerializationMode value) {
this->_schemaSerializationMode = __identifier(value);
}
inline ::System::Data::DataTableCollection^ NewDataSet::Tables::get() {
return __super::Tables;
}
inline ::System::Data::DataRelationCollection^ NewDataSet::Relations::get() {
return __super::Relations;
}
inline ::System::Void NewDataSet::InitializeDerivedDataSet() {
this->BeginInit();
this->InitClass();
this->EndInit();
}
inline ::System::Data::DataSet^ NewDataSet::Clone() {
NewDataSet^ cln = (cli::safe_cast<NewDataSet^ >(__super::Clone()));
cln->InitVars();
cln->SchemaSerializationMode = this->SchemaSerializationMode;
return cln;
}
inline ::System::Boolean NewDataSet::ShouldSerializeTables() {
return false;
}
inline ::System::Boolean NewDataSet::ShouldSerializeRelations() {
return false;
}
inline ::System::Void NewDataSet::ReadXmlSerializable(::System::Xml::XmlReader^ reader) {
if (this->DetermineSchemaSerializationMode(reader) == ::System::Data::SchemaSerializationMode::IncludeSchema) {
this->Reset();
::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet());
ds->ReadXml(reader);
this->DataSetName = ds->DataSetName;
this->Prefix = ds->Prefix;
this->Namespace = ds->Namespace;
this->Locale = ds->Locale;
this->CaseSensitive = ds->CaseSensitive;
this->EnforceConstraints = ds->EnforceConstraints;
this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add);
this->InitVars();
}
else {
this->ReadXml(reader);
this->InitVars();
}
}
inline ::System::Xml::Schema::XmlSchema^ NewDataSet::GetSchemaSerializable() {
::System::IO::MemoryStream^ stream = (gcnew ::System::IO::MemoryStream());
this->WriteXmlSchema((gcnew ::System::Xml::XmlTextWriter(stream, nullptr)));
stream->Position = 0;
return ::System::Xml::Schema::XmlSchema::Read((gcnew ::System::Xml::XmlTextReader(stream)), nullptr);
}
inline ::System::Void NewDataSet::InitVars() {
this->InitVars(true);
}
inline ::System::Void NewDataSet::InitVars(::System::Boolean initTable) {
}
inline ::System::Void NewDataSet::InitClass() {
this->DataSetName = L"NewDataSet";
this->Prefix = L"";
this->Namespace = L"http://microsoft.com/diskspd/DiskSpdConfig.xsd";
this->Locale = (gcnew ::System::Globalization::CultureInfo(L""));
this->EnforceConstraints = true;
this->SchemaSerializationMode = ::System::Data::SchemaSerializationMode::IncludeSchema;
}
inline ::System::Void NewDataSet::SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e) {
if (e->Action == ::System::ComponentModel::CollectionChangeAction::Remove) {
this->InitVars();
}
}
inline ::System::Xml::Schema::XmlSchemaComplexType^ NewDataSet::GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs) {
NewDataSet^ ds = (gcnew NewDataSet());
::System::Xml::Schema::XmlSchemaComplexType^ type = (gcnew ::System::Xml::Schema::XmlSchemaComplexType());
::System::Xml::Schema::XmlSchemaSequence^ sequence = (gcnew ::System::Xml::Schema::XmlSchemaSequence());
::System::Xml::Schema::XmlSchemaAny^ any = (gcnew ::System::Xml::Schema::XmlSchemaAny());
any->Namespace = ds->Namespace;
sequence->Items->Add(any);
type->Particle = sequence;
::System::Xml::Schema::XmlSchema^ dsSchema = ds->GetSchemaSerializable();
if (xs->Contains(dsSchema->TargetNamespace)) {
::System::IO::MemoryStream^ s1 = (gcnew ::System::IO::MemoryStream());
::System::IO::MemoryStream^ s2 = (gcnew ::System::IO::MemoryStream());
try {
::System::Xml::Schema::XmlSchema^ schema = nullptr;
dsSchema->Write(s1);
for ( ::System::Collections::IEnumerator^ schemas = xs->Schemas(dsSchema->TargetNamespace)->GetEnumerator(); schemas->MoveNext(); ) {
schema = (cli::safe_cast<::System::Xml::Schema::XmlSchema^ >(schemas->Current));
s2->SetLength(0);
schema->Write(s2);
if (s1->Length == s2->Length) {
s1->Position = 0;
s2->Position = 0;
for ( ; ((s1->Position != s1->Length)
&& (s1->ReadByte() == s2->ReadByte())); ) {
;
}
if (s1->Position == s1->Length) {
return type;
}
}
}
}
finally {
if (s1 != nullptr) {
s1->Close();
}
if (s2 != nullptr) {
s2->Close();
}
}
}
xs->Add(dsSchema);
return type;
}
@@ -0,0 +1,236 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://microsoft.com/diskspd/DiskSpdConfig.xsd"
elementFormDefault="qualified"
xmlns="http://microsoft.com/diskspd/DiskSpdConfig.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:complexType name="Profile">
<xs:all>
<xs:element name="TimeSpans" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="TimeSpan" minOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="Targets" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="Target" minOccurs="1">
<!-- file / disk -->
<xs:complexType>
<xs:all>
<!-- string _sPath -->
<xs:element name="Path" type="xs:string" minOccurs="1" maxOccurs="1"></xs:element>
<!-- DWORD dwBlockSize -->
<xs:element name="BlockSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullStrideSize -->
<xs:element name="StrideSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullBaseFileOffset -->
<xs:element name="BaseFileOffset" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bSequentialScan (open file with the FILE_FLAG_SEQUENTIAL_SCAN flag) -->
<xs:element name="SequentialScan" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bRandomAccess (open file with the FILE_FLAG_RANDOM_ACCESS flag) -->
<xs:element name="RandomAccess" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bUseLargePages (Use large pages for IO buffers) -->
<xs:element name="UseLargePages" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwRequestCount -->
<!-- -o<count> number of overlapped I/O requests per file per thread
(1=synchronous I/O, unless more than 1 thread is specified with -F) [default=2]-->
<xs:element name="RequestCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullRandom
-r<align>[K|M|G|b] random I/O aligned to <align> bytes (doesn't make sense with -s)
<align> can be stated in bytes/KB/MB/GB/blocks [default access=sequential, default alignment=block size] -->
<xs:element name="Random" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bDisableOSCache -->
<xs:element name="DisableOSCache" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bDisableAllCache -->
<xs:element name="DisableAllCache" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<xs:element name="WriteBufferContent" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="Pattern">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="sequential"></xs:enumeration>
<xs:enumeration value="zero"></xs:enumeration>
<xs:enumeration value="random"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!-- used only with pattern == random -->
<xs:element name="RandomDataSource">
<xs:complexType>
<xs:all>
<xs:element name="SizeInBytes" type="xs:unsignedLong" minOccurs="1" maxOccurs="1"></xs:element>
<xs:element name="FilePath" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
<!-- DWORD dwBurstSize (number of IOs in a burst) -->
<xs:element name="BurstSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwThinkTime (time to pause before issuing the next burst of IOs) -->
<xs:element name="ThinkTime" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwThroughput (in bytes per millisecond); this can not be specified when using completion routines -->
<xs:element name="Throughput" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwThreadsPerFile -->
<xs:element name="ThreadsPerFile" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullFileSize -->
<!-- used by the -c (create file) switch-->
<xs:element name="FileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullMaxFileSize -->
<xs:element name="MaxFileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT32 ulWriteRatio -->
<xs:element name="WriteRatio" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bParallelAsyncIO
-p start async (overlapped) I/O operations with the same offset (makes sense only with -o2 or grater) -->
<xs:element name="ParallelAsyncIO" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT64 ullThreadStride -->
<xs:element name="ThreadStride" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
<!-- 0 - not set, 1 - very low, 2 - low, 3 - normal -->
<xs:element name="IOPriority" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- UINT32 ulDuration -->
<xs:element name="Duration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT32 ulWarmUp -->
<xs:element name="Warmup" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT32 ulCoolDown -->
<xs:element name="Cooldown" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT32 ulRandSeed
-z set random seed [default=0 if parameter not provided, GetTickCount() if value not provided] -->
<xs:element name="RandSeed" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwThreadCount
-F<count> total number of threads (cannot be used with -t) this cannot be used if per-file thread count is provided -->
<xs:element name="ThreadCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bGroupAffinity -->
<xs:element name="GroupAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- UINT32 *puAffinity -->
<xs:element name="Affinity" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="AffinityAssignment" type="xs:unsignedInt" minOccurs="1"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- BOOL bDisableAffinity
-n disable affinity (cannot be used with -a) -->
<xs:element name="DisableAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bCompletionRoutines -->
<!-- TODO: this should be decided on a target level -->
<xs:element name="CompletionRoutines" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<xs:element name="MeasureLatency" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<xs:element name="CalculateIopsStdDev" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<xs:element name="IoBucketDuration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
<!-- BOOL bVerbose -->
<xs:element name="Verbose" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- DWORD dwProgress -->
<xs:element name="Progress" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
<xs:element name="ResultFormat" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="text"></xs:enumeration>
<xs:enumeration value="xml"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!-- ETWMask -->
<xs:element name="ETW">
<xs:complexType>
<xs:all>
<!-- BOOL bProcess -->
<xs:element name="Process" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bThread -->
<xs:element name="Thread" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bImageLoad -->
<xs:element name="ImageLoad" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bDiskIO -->
<xs:element name="DiskIO" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bMemoryPageFaults -->
<xs:element name="MemoryPageFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bMemoryHardFaults -->
<xs:element name="MemoryHardFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bNetwork -->
<xs:element name="Network" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bRegistry -->
<xs:element name="Registry" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bUsePagedMemory -->
<xs:element name="UsePagedMemory" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bUsePerfTimer -->
<xs:element name="UsePerfTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bUseSystemTimer -->
<xs:element name="UseSystemTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
<!-- BOOL bUseCyclesCounter -->
<xs:element name="UseCyclesCounter" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
</xs:all>
</xs:complexType>
</xs:element>
<!-- files should be created before the first time span -->
<xs:element name="PrecreateFiles" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<!-- if the same path exists in multiple time spans, the max size will be used -->
<xs:enumeration value="UseMaxSize"></xs:enumeration>
<xs:enumeration value="CreateOnlyFilesWithConstantSizes"></xs:enumeration>
<xs:enumeration value="CreateOnlyFilesWithConstantOrZeroSizes"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,482 @@
/*
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 "xmlresultparser.h"
// TODO: refactor to a single function shared with the ResultParser
void XmlResultParser::_Print(const char *format, ...)
{
assert(nullptr != format);
va_list listArg;
va_start(listArg, format);
char buffer[4096] = {};
vsprintf_s(buffer, _countof(buffer), format, listArg);
va_end(listArg);
_sResult += buffer;
}
void XmlResultParser::_PrintTargetResults(const TargetResults& results)
{
// TODO: results.readBucketizer;
// TODO: results.writeBucketizer;
_Print("<Path>%s</Path>\n", results.sPath.c_str());
_Print("<BytesCount>%I64u</BytesCount>\n", results.ullBytesCount);
_Print("<FileSize>%I64u</FileSize>\n", results.ullFileSize);
_Print("<IOCount>%I64u</IOCount>\n", results.ullIOCount);
_Print("<ReadBytes>%I64u</ReadBytes>\n", results.ullReadBytesCount);
_Print("<ReadCount>%I64u</ReadCount>\n", results.ullReadIOCount);
_Print("<WriteBytes>%I64u</WriteBytes>\n", results.ullWriteBytesCount);
_Print("<WriteCount>%I64u</WriteCount>\n", results.ullWriteIOCount);
}
void XmlResultParser::_PrintTargetLatency(const TargetResults& results)
{
if (results.readLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageReadLatencyMilliseconds>%.3f</AverageReadLatencyMilliseconds>\n", results.readLatencyHistogram.GetAvg() / 1000);
_Print("<ReadLatencyStdev>%.3f</ReadLatencyStdev>\n", results.readLatencyHistogram.GetStandardDeviation() / 1000);
}
if (results.writeLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageWriteLatencyMilliseconds>%.3f</AverageWriteLatencyMilliseconds>\n", results.writeLatencyHistogram.GetAvg() / 1000);
_Print("<WriteLatencyStdev>%.3f</WriteLatencyStdev>\n", results.writeLatencyHistogram.GetStandardDeviation() / 1000);
}
Histogram<float> totalLatencyHistogram;
totalLatencyHistogram.Merge(results.readLatencyHistogram);
totalLatencyHistogram.Merge(results.writeLatencyHistogram);
if (totalLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageLatencyMilliseconds>%.3f</AverageLatencyMilliseconds>\n", totalLatencyHistogram.GetAvg() / 1000);
_Print("<LatencyStdev>%.3f</LatencyStdev>\n", totalLatencyHistogram.GetStandardDeviation() / 1000);
}
}
void XmlResultParser::_PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs)
{
_Print("<Iops>\n");
IoBucketizer totalIoBucketizer;
totalIoBucketizer.Merge(readBucketizer);
totalIoBucketizer.Merge(writeBucketizer);
if (readBucketizer.GetNumberOfValidBuckets() > 0)
{
_Print("<ReadIopsStdDev>%.3f</ReadIopsStdDev>\n", readBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0));
}
if (writeBucketizer.GetNumberOfValidBuckets() > 0)
{
_Print("<WriteIopsStdDev>%.3f</WriteIopsStdDev>\n", writeBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0));
}
if (totalIoBucketizer.GetNumberOfValidBuckets() > 0)
{
_Print("<IopsStdDev>%.3f</IopsStdDev>\n", totalIoBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0));
}
_PrintIops(readBucketizer, writeBucketizer, bucketTimeInMs);
_Print("</Iops>\n");
}
void XmlResultParser::_PrintETWSessionInfo(struct ETWSessionInfo sessionInfo)
{
_Print("<ETWSessionInfo>\n");
_Print("<BufferSizeKB>%lu</BufferSizeKB>\n", sessionInfo.ulBufferSize);
_Print("<MinimimBuffers>%lu</MinimimBuffers>\n", sessionInfo.ulMinimumBuffers);
_Print("<MaximumBuffers>%lu</MaximumBuffers>\n", sessionInfo.ulMaximumBuffers);
_Print("<FreeBuffers>%lu</FreeBuffers>", sessionInfo.ulFreeBuffers);
_Print("<BuffersWritten>%lu</BuffersWritten>\n", sessionInfo.ulBuffersWritten);
_Print("<FlushTimerSeconds>%lu</FlushTimerSeconds>\n", sessionInfo.ulFlushTimer);
_Print("<AgeLimitMinues>%d</AgeLimitMinues>\n", sessionInfo.lAgeLimit);
_Print("<AllocatedBuffers>%lu</AllocatedBuffers>\n", sessionInfo.ulNumberOfBuffers);
_Print("<LostEvents>%15lu</LostEvents>\n", sessionInfo.ulEventsLost);
_Print("<LostLogBuffers>%10lu</LostLogBuffers>\n", sessionInfo.ulLogBuffersLost);
_Print("<LostRealTimeBuffers>%4lu</LostRealTimeBuffers>\n", sessionInfo.ulRealTimeBuffersLost);
_Print("</ETWSessionInfo>\n");
}
void XmlResultParser::_PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters)
{
_Print("<ETW>\n");
if (ETWMask.bDiskIO)
{
_Print("<DiskIO>\n");
_Print("<Read>%I64u</Read>\n", EtwEventCounters.ullIORead);
_Print("<Write>%I64u</Write>\n", EtwEventCounters.ullIOWrite);
_Print("</DiskIO>\n");
}
if (ETWMask.bImageLoad)
{
_Print("<LoadImage>%I64u</LoadImage>\n", EtwEventCounters.ullImageLoad);
}
if (ETWMask.bMemoryPageFaults)
{
_Print("<MemoryPageFaults>\n");
_Print("<CopyOnWrite>%I64u</CopyOnWrite>\n", EtwEventCounters.ullMMCopyOnWrite);
_Print("<DemandZeroFault>%I64u</DemandZeroFault>\n", EtwEventCounters.ullMMDemandZeroFault);
_Print("<GuardPageFault>%I64u</GuardPageFault>\n", EtwEventCounters.ullMMGuardPageFault);
_Print("<HardPageFault>%I64u</HardPageFault>\n", EtwEventCounters.ullMMHardPageFault);
_Print("<TransitionFault>%I64u</TransitionFault>\n", EtwEventCounters.ullMMTransitionFault);
_Print("</MemoryPageFaults>\n");
}
if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults)
{
_Print("<HardPageFault>%I64u</HardPageFault>\n", EtwEventCounters.ullMMHardPageFault);
}
if (ETWMask.bNetwork)
{
_Print("<Network>\n");
_Print("<Accept>%I64u</Accept>\n", EtwEventCounters.ullNetAccept);
_Print("<Connect>%I64u</Connect>\n", EtwEventCounters.ullNetConnect);
_Print("<Disconnect>%I64u</Disconnect>\n", EtwEventCounters.ullNetDisconnect);
_Print("<Reconnect>%I64u</Reconnect>\n", EtwEventCounters.ullNetReconnect);
_Print("<Retransmit>%I64u</Retransmit>\n", EtwEventCounters.ullNetRetransmit);
_Print("<TCPIPSend>%I64u</TCPIPSend>\n", EtwEventCounters.ullNetTcpSend);
_Print("<TCPIPReceive>%I64u</TCPIPReceive>\n", EtwEventCounters.ullNetTcpReceive);
_Print("<UDPIPSend>%I64u</UDPIPSend>\n", EtwEventCounters.ullNetUdpSend);
_Print("<UDPIPReceive>%I64u</UDPIPReceive>\n", EtwEventCounters.ullNetUdpReceive);
_Print("</Network>\n");
}
if (ETWMask.bProcess)
{
_Print("<Process>\n");
_Print("<Start>%I64u</Start>\n", EtwEventCounters.ullProcessStart);
_Print("<End>%I64u</End>\n", EtwEventCounters.ullProcessEnd);
_Print("</Process>\n");
}
if (ETWMask.bRegistry)
{
_Print("<Registry>\n");
_Print("<NtCreateKey>%I64u</NtCreateKey>\n", EtwEventCounters.ullRegCreate);
_Print("<NtDeleteKey>%I64u</NtDeleteKey>\n", EtwEventCounters.ullRegDelete);
_Print("<NtDeleteValueKey>%I64u</NtDeleteValueKey>\n", EtwEventCounters.ullRegDeleteValue);
_Print("<NtEnumerateKey>%I64u</NtEnumerateKey>\n", EtwEventCounters.ullRegEnumerateKey);
_Print("<NtEnumerateValueKey>%I64u</NtEnumerateValueKey>\n", EtwEventCounters.ullRegEnumerateValueKey);
_Print("<NtFlushKey>%I64u</NtFlushKey>\n", EtwEventCounters.ullRegFlush);
_Print("<KcbDump>%I64u</KcbDump>\n", EtwEventCounters.ullRegKcbDmp);
_Print("<NtOpenKey>%I64u</NtOpenKey>\n", EtwEventCounters.ullRegOpen);
_Print("<NtQueryKey>%I64u</NtQueryKey>\n", EtwEventCounters.ullRegQuery);
_Print("<NtQueryMultipleValueKey>%I64u</NtQueryMultipleValueKey>\n", EtwEventCounters.ullRegQueryMultipleValue);
_Print("<NtQueryValueKey>%I64u</NtQueryValueKey>\n", EtwEventCounters.ullRegQueryValue);
_Print("<NtSetInformationKey>%I64u</NtSetInformationKey>\n", EtwEventCounters.ullRegSetInformation);
_Print("<NtSetValueKey>%I64u</NtSetValueKey>\n", EtwEventCounters.ullRegSetValue);
_Print("</Registry>\n");
}
if (ETWMask.bThread)
{
_Print("<Thread>\n");
_Print("<Start>%I64u</Start>\n", EtwEventCounters.ullThreadStart);
_Print("<End>%I64u</End>\n", EtwEventCounters.ullThreadEnd);
_Print("</Thread>\n");
}
_Print("</ETW>\n");
}
void XmlResultParser::_PrintCpuUtilization(const Results& results)
{
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount);
_Print("<CpuUtilization>\n");
double busyTime = 0;
double totalIdleTime = 0;
double totalUserTime = 0;
double totalKrnlTime = 0;
for (unsigned int x = 0; x<ulProcCount; ++x)
{
double idleTime;
double userTime;
double krnlTime;
double thisTime;
idleTime = 100.0 * results.vSystemProcessorPerfInfo[x].IdleTime.QuadPart / 10000000 / fTime;
krnlTime = 100.0 * results.vSystemProcessorPerfInfo[x].KernelTime.QuadPart / 10000000 / fTime;
userTime = 100.0 * results.vSystemProcessorPerfInfo[x].UserTime.QuadPart / 10000000 / fTime;
thisTime = (krnlTime + userTime) - idleTime;
_Print("<CPU>\n");
_Print("<Id>%d</Id>\n", x);
_Print("<UsagePercent>%.2f</UsagePercent>\n", thisTime);
_Print("<UserPercent>%.2f</UserPercent>\n", userTime);
_Print("<KernelPercent>%.2f</KernelPercent>\n", krnlTime - idleTime);
_Print("<IdlePercent>%.2f</IdlePercent>\n", idleTime);
_Print("</CPU>\n");
busyTime += thisTime;
totalIdleTime += idleTime;
totalUserTime += userTime;
totalKrnlTime += krnlTime;
}
_Print("<Average>\n");
_Print("<UsagePercent>%.2f</UsagePercent>\n", busyTime / ulProcCount);
_Print("<UserPercent>%.2f</UserPercent>\n", totalUserTime / ulProcCount);
_Print("<KernelPercent>%.2f</KernelPercent>\n", (totalKrnlTime - totalIdleTime) / ulProcCount);
_Print("<IdlePercent>%.2f</IdlePercent>\n", totalIdleTime / ulProcCount);
_Print("</Average>\n");
_Print("</CpuUtilization>\n");
}
// emit the iops time series (this obviates needing perfmon counters, in common cases, and provides file level data)
void XmlResultParser::_PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs)
{
bool done = false;
for (size_t i = 0; !done; i++)
{
done = true;
double r = 0.0;
double w = 0.0;
if (readBucketizer.GetNumberOfValidBuckets() > i)
{
r = readBucketizer.GetIoBucket(i) / (bucketTimeInMs / 1000.0);
done = false;
}
if (writeBucketizer.GetNumberOfValidBuckets() > i)
{
w = writeBucketizer.GetIoBucket(i) / (bucketTimeInMs / 1000.0);
done = false;
}
if (!done)
{
_Print("<Bucket SampleMillisecond=\"%lu\" Read=\"%.0f\" Write=\"%.0f\" Total=\"%.0f\"/>\n", bucketTimeInMs*(i + 1), r, w, r + w);
}
}
}
void XmlResultParser::_PrintOverallIops(const Results& results, UINT32 bucketTimeInMs)
{
IoBucketizer readBucketizer;
IoBucketizer writeBucketizer;
for (const auto& thread : results.vThreadResults)
{
for (const auto& target : thread.vTargetResults)
{
readBucketizer.Merge(target.readBucketizer);
writeBucketizer.Merge(target.writeBucketizer);
}
}
_PrintTargetIops(readBucketizer, writeBucketizer, bucketTimeInMs);
}
void XmlResultParser::_PrintLatencyPercentiles(const Results& results)
{
Histogram<float> readLatencyHistogram;
Histogram<float> writeLatencyHistogram;
Histogram<float> totalLatencyHistogram;
for (const auto& thread : results.vThreadResults)
{
for (const auto& target : thread.vTargetResults)
{
readLatencyHistogram.Merge(target.readLatencyHistogram);
writeLatencyHistogram.Merge(target.writeLatencyHistogram);
totalLatencyHistogram.Merge(target.writeLatencyHistogram);
totalLatencyHistogram.Merge(target.readLatencyHistogram);
}
}
_Print("<Latency>\n");
if (readLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageReadMilliseconds>%.3f</AverageReadMilliseconds>\n", readLatencyHistogram.GetAvg() / 1000);
_Print("<ReadLatencyStdev>%.3f</ReadLatencyStdev>\n", readLatencyHistogram.GetStandardDeviation() / 1000);
}
if (writeLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageWriteMilliseconds>%.3f</AverageWriteMilliseconds>\n", writeLatencyHistogram.GetAvg() / 1000);
_Print("<WriteLatencyStdev>%.3f</WriteLatencyStdev>\n", writeLatencyHistogram.GetStandardDeviation() / 1000);
}
if (totalLatencyHistogram.GetSampleSize() > 0)
{
_Print("<AverageTotalMilliseconds>%.3f</AverageTotalMilliseconds>\n", totalLatencyHistogram.GetAvg() / 1000);
_Print("<LatencyStdev>%.3f</LatencyStdev>\n", totalLatencyHistogram.GetStandardDeviation() / 1000);
}
_Print("<Bucket>\n");
_Print("<Percentile>0</Percentile>\n");
if (readLatencyHistogram.GetSampleSize() > 0)
{
_Print("<ReadMilliseconds>%.3f</ReadMilliseconds>\n", readLatencyHistogram.GetMin() / 1000);
}
if (writeLatencyHistogram.GetSampleSize() > 0)
{
_Print("<WriteMilliseconds>%.3f</WriteMilliseconds>\n", writeLatencyHistogram.GetMin() / 1000);
}
if (totalLatencyHistogram.GetSampleSize() > 0)
{
_Print("<TotalMilliseconds>%.3f</TotalMilliseconds>\n", totalLatencyHistogram.GetMin() / 1000);
}
_Print("</Bucket>\n");
// Construct vector of percentiles and decimal precision to squelch trailing zeroes. This is more
// detailed than summary text output, and does not contain the decorated names (15th, etc.)
vector<pair<int, double>> vPercentiles;
for (int p = 1; p <= 99; p++)
{
vPercentiles.push_back(make_pair(0, p));
}
vPercentiles.push_back(make_pair(1, 99.9));
vPercentiles.push_back(make_pair(2, 99.99));
vPercentiles.push_back(make_pair(3, 99.999));
vPercentiles.push_back(make_pair(4, 99.9999));
vPercentiles.push_back(make_pair(5, 99.99999));
vPercentiles.push_back(make_pair(6, 99.999999));
for (auto p : vPercentiles)
{
_Print("<Bucket>\n");
_Print("<Percentile>%.*f</Percentile>\n", p.first, p.second);
if (readLatencyHistogram.GetSampleSize() > 0)
{
_Print("<ReadMilliseconds>%.3f</ReadMilliseconds>\n", readLatencyHistogram.GetPercentile(p.second / 100) / 1000);
}
if (writeLatencyHistogram.GetSampleSize() > 0)
{
_Print("<WriteMilliseconds>%.3f</WriteMilliseconds>\n", writeLatencyHistogram.GetPercentile(p.second / 100) / 1000);
}
if (totalLatencyHistogram.GetSampleSize() > 0)
{
_Print("<TotalMilliseconds>%.3f</TotalMilliseconds>\n", totalLatencyHistogram.GetPercentile(p.second / 100) / 1000);
}
_Print("</Bucket>\n");
}
_Print("<Bucket>\n");
_Print("<Percentile>100</Percentile>\n");
if (readLatencyHistogram.GetSampleSize() > 0)
{
_Print("<ReadMilliseconds>%.3f</ReadMilliseconds>\n", readLatencyHistogram.GetMax() / 1000);
}
if (writeLatencyHistogram.GetSampleSize() > 0)
{
_Print("<WriteMilliseconds>%.3f</WriteMilliseconds>\n", writeLatencyHistogram.GetMax() / 1000);
}
if (totalLatencyHistogram.GetSampleSize() > 0)
{
_Print("<TotalMilliseconds>%.3f</TotalMilliseconds>\n", totalLatencyHistogram.GetMax() / 1000);
}
_Print("</Bucket>\n");
_Print("</Latency>\n");
}
int XmlResultParser::GetTotalScore()
{
return 0;
}
double XmlResultParser::GetAverageLatency()
{
return 0.0;
}
string XmlResultParser::ParseResults(Profile& profile, const SystemInformation& system, vector<Results> vResults)
{
_sResult.clear();
_Print("<Results>\n");
_sResult += system.GetXml();
_sResult += profile.GetXml();
for (size_t iResults = 0; iResults < vResults.size(); iResults++)
{
const Results& results = vResults[iResults];
const TimeSpan& timeSpan = profile.GetTimeSpans()[iResults];
_Print("<TimeSpan>\n");
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration
if (fTime >= 0.0000001)
{
// There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file.
// In the latter case vThreadResults.size() == number of threads per file * file count
size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size();
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
_Print("<TestTimeSeconds>%.2f</TestTimeSeconds>\n", fTime);
_Print("<ThreadCount>%u</ThreadCount>\n", ulThreadCnt);
_Print("<ProcCount>%u</ProcCount>\n", ulProcCount);
_PrintCpuUtilization(results);
if (timeSpan.GetMeasureLatency())
{
_PrintLatencyPercentiles(results);
}
if (timeSpan.GetCalculateIopsStdDev())
{
_PrintOverallIops(results, timeSpan.GetIoBucketDurationInMilliseconds());
}
if (results.fUseETW)
{
_PrintETW(results.EtwMask, results.EtwEventCounters);
_PrintETWSessionInfo(results.EtwSessionInfo);
}
for (size_t iThread = 0; iThread < results.vThreadResults.size(); iThread++)
{
const ThreadResults& threadResults = results.vThreadResults[iThread];
_Print("<Thread>\n");
_Print("<Id>%u</Id>\n", iThread);
for (const auto& targetResults : threadResults.vTargetResults)
{
_Print("<Target>\n");
_PrintTargetResults(targetResults);
if (timeSpan.GetMeasureLatency())
{
_PrintTargetLatency(targetResults);
}
if (timeSpan.GetCalculateIopsStdDev())
{
_PrintTargetIops(targetResults.readBucketizer, targetResults.writeBucketizer, timeSpan.GetIoBucketDurationInMilliseconds());
}
_Print("</Target>\n");
}
_Print("</Thread>\n");
}
}
else
{
_Print("<Error>The test was interrupted before the measurements began. No results are displayed.</Error>\n");
}
_Print("</TimeSpan>\n");
}
_Print("</Results>");
return _sResult;
}
@@ -0,0 +1,53 @@
/*
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(Profile& profile, const SystemInformation& system, vector<Results> vResults);
int GetTotalScore();
double GetAverageLatency();
private:
void _PrintCpuUtilization(const Results& results);
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 _Print(const char *format, ...);
string _sResult;
};
@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0EF5CE78-8E92-4A1B-A255-0F544AADA291}</ProjectGuid>
<RootNamespace>CmdLineParser</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\CmdLineParser\CmdLineParser.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\CmdLineParser\CmdLineParser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}</ProjectGuid>
<RootNamespace>CmdRequestCreator</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
<TargetName>diskspd</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
<TargetName>diskspd</TargetName>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
<TargetName>diskspd32</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
<TargetName>diskspd64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>fileextd.lib;$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/SUBSYSTEM:CONSOLE,5.01 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>fileextd.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/SUBSYSTEM:CONSOLE,5.02 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\CmdLineParser\CmdLineParser.vcxproj">
<Project>{0ef5ce78-8e92-4a1b-a255-0f544aada291}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\CmdRequestCreator\CmdRequestCreator.h" />
<ClInclude Include="..\..\CmdRequestCreator\errors.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\CmdRequestCreator\CmdRequestCreator.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B253AB42-F482-417A-82CE-EDAFCD26F366}</ProjectGuid>
<RootNamespace>Common</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\Common\Common.cpp" />
<ClCompile Include="..\..\Common\IoBucketizer.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Common\Common.h" />
<ClInclude Include="..\..\Common\Histogram.h" />
<ClInclude Include="..\..\Common\IoBucketizer.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{62DB1E99-FBA0-45FD-9355-423059BA03B8}</ProjectGuid>
<RootNamespace>IORequestGenerator</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def</ModuleDefinitionFile>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def</ModuleDefinitionFile>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\IORequestGenerator\etw.h" />
<ClInclude Include="..\..\IORequestGenerator\IORequestGenerator.h" />
<ClInclude Include="..\..\IORequestGenerator\OverlappedQueue.h" />
<ClInclude Include="..\..\IORequestGenerator\ThroughputMeter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\IORequestGenerator\etw.cpp" />
<ClCompile Include="..\..\IORequestGenerator\IORequestGenerator.cpp" />
<ClCompile Include="..\..\IORequestGenerator\OverlappedQueue.cpp" />
<ClCompile Include="..\..\IORequestGenerator\ThroughputMeter.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F6C211DC-B076-4716-BCDC-D7DE88973B66}</ProjectGuid>
<RootNamespace>ResultParser</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def</ModuleDefinitionFile>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def</ModuleDefinitionFile>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\ResultParser\ResultParser.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\ResultParser\ResultParser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{EFF06674-B068-45F1-9661-DB9363B025B3}</ProjectGuid>
<RootNamespace>XmlProfileParser</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\XmlProfileParser\XmlProfileParser.h" />
<ClInclude Include="diskspd.h">
<DependentUpon>..\..\XmlProfileParser\diskspd.xsd</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Xsd Include="..\..\XmlProfileParser\diskspd.xsd" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\XmlProfileParser\XmlProfileParser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,277 @@
#pragma once
#using <mscorlib.dll>
#using <System.dll>
#using <System.Data.dll>
#using <System.Xml.dll>
using namespace System::Security::Permissions;
[assembly:SecurityPermissionAttribute(SecurityAction::RequestMinimum, SkipVerification=false)];
//
// このソース コードは xsd によって自動生成されました。Version=4.6.1055.0 です。
//
namespace XmlProfileParser {
using namespace System;
ref class NewDataSet;
/// <summary>
///Represents a strongly typed in-memory cache of data.
///</summary>
[System::Serializable,
System::ComponentModel::DesignerCategoryAttribute(L"code"),
System::ComponentModel::ToolboxItem(true),
System::Xml::Serialization::XmlSchemaProviderAttribute(L"GetTypedDataSetSchema"),
System::Xml::Serialization::XmlRootAttribute(L"NewDataSet"),
System::ComponentModel::Design::HelpKeywordAttribute(L"vs.data.DataSet")]
public ref class NewDataSet : public ::System::Data::DataSet {
private: ::System::Data::SchemaSerializationMode _schemaSerializationMode;
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
NewDataSet();
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context);
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::BrowsableAttribute(true),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Visible)]
virtual property ::System::Data::SchemaSerializationMode SchemaSerializationMode {
::System::Data::SchemaSerializationMode get() override;
System::Void set(::System::Data::SchemaSerializationMode value) override;
}
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)]
property ::System::Data::DataTableCollection^ Tables {
::System::Data::DataTableCollection^ get() new;
}
public: [System::Diagnostics::DebuggerNonUserCodeAttribute,
System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"),
System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)]
property ::System::Data::DataRelationCollection^ Relations {
::System::Data::DataRelationCollection^ get() new;
}
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Void InitializeDerivedDataSet() override;
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Data::DataSet^ Clone() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Boolean ShouldSerializeTables() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Boolean ShouldSerializeRelations() override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Void ReadXmlSerializable(::System::Xml::XmlReader^ reader) override;
protected: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
virtual ::System::Xml::Schema::XmlSchema^ GetSchemaSerializable() override;
internal: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitVars();
internal: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitVars(::System::Boolean initTable);
private: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void InitClass();
private: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
::System::Void SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e);
public: [System::Diagnostics::DebuggerNonUserCodeAttribute]
[System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")]
static ::System::Xml::Schema::XmlSchemaComplexType^ GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs);
};
}
namespace XmlProfileParser {
inline NewDataSet::NewDataSet() {
this->BeginInit();
this->InitClass();
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged);
__super::Tables->CollectionChanged += schemaChangedHandler;
__super::Relations->CollectionChanged += schemaChangedHandler;
this->EndInit();
}
inline NewDataSet::NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context) :
::System::Data::DataSet(info, context, false) {
if (this->IsBinarySerialized(info, context) == true) {
this->InitVars(false);
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler1 = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged);
this->Tables->CollectionChanged += schemaChangedHandler1;
this->Relations->CollectionChanged += schemaChangedHandler1;
return;
}
::System::String^ strSchema = (cli::safe_cast<::System::String^ >(info->GetValue(L"XmlSchema", ::System::String::typeid)));
if (this->DetermineSchemaSerializationMode(info, context) == ::System::Data::SchemaSerializationMode::IncludeSchema) {
::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet());
ds->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema)))));
this->DataSetName = ds->DataSetName;
this->Prefix = ds->Prefix;
this->Namespace = ds->Namespace;
this->Locale = ds->Locale;
this->CaseSensitive = ds->CaseSensitive;
this->EnforceConstraints = ds->EnforceConstraints;
this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add);
this->InitVars();
}
else {
this->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema)))));
}
this->GetSerializationData(info, context);
::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged);
__super::Tables->CollectionChanged += schemaChangedHandler;
this->Relations->CollectionChanged += schemaChangedHandler;
}
inline ::System::Data::SchemaSerializationMode NewDataSet::SchemaSerializationMode::get() {
return this->_schemaSerializationMode;
}
inline System::Void NewDataSet::SchemaSerializationMode::set(::System::Data::SchemaSerializationMode value) {
this->_schemaSerializationMode = __identifier(value);
}
inline ::System::Data::DataTableCollection^ NewDataSet::Tables::get() {
return __super::Tables;
}
inline ::System::Data::DataRelationCollection^ NewDataSet::Relations::get() {
return __super::Relations;
}
inline ::System::Void NewDataSet::InitializeDerivedDataSet() {
this->BeginInit();
this->InitClass();
this->EndInit();
}
inline ::System::Data::DataSet^ NewDataSet::Clone() {
XmlProfileParser::NewDataSet^ cln = (cli::safe_cast<XmlProfileParser::NewDataSet^ >(__super::Clone()));
cln->InitVars();
cln->SchemaSerializationMode = this->SchemaSerializationMode;
return cln;
}
inline ::System::Boolean NewDataSet::ShouldSerializeTables() {
return false;
}
inline ::System::Boolean NewDataSet::ShouldSerializeRelations() {
return false;
}
inline ::System::Void NewDataSet::ReadXmlSerializable(::System::Xml::XmlReader^ reader) {
if (this->DetermineSchemaSerializationMode(reader) == ::System::Data::SchemaSerializationMode::IncludeSchema) {
this->Reset();
::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet());
ds->ReadXml(reader);
this->DataSetName = ds->DataSetName;
this->Prefix = ds->Prefix;
this->Namespace = ds->Namespace;
this->Locale = ds->Locale;
this->CaseSensitive = ds->CaseSensitive;
this->EnforceConstraints = ds->EnforceConstraints;
this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add);
this->InitVars();
}
else {
this->ReadXml(reader);
this->InitVars();
}
}
inline ::System::Xml::Schema::XmlSchema^ NewDataSet::GetSchemaSerializable() {
::System::IO::MemoryStream^ stream = (gcnew ::System::IO::MemoryStream());
this->WriteXmlSchema((gcnew ::System::Xml::XmlTextWriter(stream, nullptr)));
stream->Position = 0;
return ::System::Xml::Schema::XmlSchema::Read((gcnew ::System::Xml::XmlTextReader(stream)), nullptr);
}
inline ::System::Void NewDataSet::InitVars() {
this->InitVars(true);
}
inline ::System::Void NewDataSet::InitVars(::System::Boolean initTable) {
}
inline ::System::Void NewDataSet::InitClass() {
this->DataSetName = L"NewDataSet";
this->Prefix = L"";
this->Namespace = L"http://microsoft.com/diskspd/DiskSpdConfig.xsd";
this->Locale = (gcnew ::System::Globalization::CultureInfo(L""));
this->EnforceConstraints = true;
this->SchemaSerializationMode = ::System::Data::SchemaSerializationMode::IncludeSchema;
}
inline ::System::Void NewDataSet::SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e) {
if (e->Action == ::System::ComponentModel::CollectionChangeAction::Remove) {
this->InitVars();
}
}
inline ::System::Xml::Schema::XmlSchemaComplexType^ NewDataSet::GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs) {
XmlProfileParser::NewDataSet^ ds = (gcnew XmlProfileParser::NewDataSet());
::System::Xml::Schema::XmlSchemaComplexType^ type = (gcnew ::System::Xml::Schema::XmlSchemaComplexType());
::System::Xml::Schema::XmlSchemaSequence^ sequence = (gcnew ::System::Xml::Schema::XmlSchemaSequence());
::System::Xml::Schema::XmlSchemaAny^ any = (gcnew ::System::Xml::Schema::XmlSchemaAny());
any->Namespace = ds->Namespace;
sequence->Items->Add(any);
type->Particle = sequence;
::System::Xml::Schema::XmlSchema^ dsSchema = ds->GetSchemaSerializable();
if (xs->Contains(dsSchema->TargetNamespace)) {
::System::IO::MemoryStream^ s1 = (gcnew ::System::IO::MemoryStream());
::System::IO::MemoryStream^ s2 = (gcnew ::System::IO::MemoryStream());
try {
::System::Xml::Schema::XmlSchema^ schema = nullptr;
dsSchema->Write(s1);
for ( ::System::Collections::IEnumerator^ schemas = xs->Schemas(dsSchema->TargetNamespace)->GetEnumerator(); schemas->MoveNext(); ) {
schema = (cli::safe_cast<::System::Xml::Schema::XmlSchema^ >(schemas->Current));
s2->SetLength(0);
schema->Write(s2);
if (s1->Length == s2->Length) {
s1->Position = 0;
s2->Position = 0;
for ( ; ((s1->Position != s1->Length)
&& (s1->ReadByte() == s2->ReadByte())); ) {
;
}
if (s1->Position == s1->Length) {
return type;
}
}
}
}
finally {
if (s1 != nullptr) {
s1->Close();
}
if (s2 != nullptr) {
s2->Close();
}
}
}
xs->Add(dsSchema);
return type;
}
}
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{60A28E9C-C245-4D99-9C1C-EC911031743F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>XmlResultParser</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\..\Common;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\XmlResultParser\xmlresultparser.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\XmlResultParser\xmlresultparser.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,96 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdLineParser", "CmdLineParser\CmdLineParser.vcxproj", "{0EF5CE78-8E92-4A1B-A255-0F544AADA291}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdRequestCreator", "CmdRequestCreator\CmdRequestCreator.vcxproj", "{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}"
ProjectSection(ProjectDependencies) = postProject
{B253AB42-F482-417A-82CE-EDAFCD26F366} = {B253AB42-F482-417A-82CE-EDAFCD26F366}
{EFF06674-B068-45F1-9661-DB9363B025B3} = {EFF06674-B068-45F1-9661-DB9363B025B3}
{0EF5CE78-8E92-4A1B-A255-0F544AADA291} = {0EF5CE78-8E92-4A1B-A255-0F544AADA291}
{62DB1E99-FBA0-45FD-9355-423059BA03B8} = {62DB1E99-FBA0-45FD-9355-423059BA03B8}
{60A28E9C-C245-4D99-9C1C-EC911031743F} = {60A28E9C-C245-4D99-9C1C-EC911031743F}
{F6C211DC-B076-4716-BCDC-D7DE88973B66} = {F6C211DC-B076-4716-BCDC-D7DE88973B66}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IORequestGenerator", "IORequestGenerator\IORequestGenerator.vcxproj", "{62DB1E99-FBA0-45FD-9355-423059BA03B8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ResultParser", "ResultParser\ResultParser.vcxproj", "{F6C211DC-B076-4716-BCDC-D7DE88973B66}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlProfileParser", "XmlProfileParser\XmlProfileParser.vcxproj", "{EFF06674-B068-45F1-9661-DB9363B025B3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{B253AB42-F482-417A-82CE-EDAFCD26F366}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlResultParser", "XmlResultParser\XmlResultParser.vcxproj", "{60A28E9C-C245-4D99-9C1C-EC911031743F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.ActiveCfg = Debug|Win32
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.Build.0 = Debug|Win32
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.ActiveCfg = Debug|x64
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.Build.0 = Debug|x64
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.ActiveCfg = Release|Win32
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.Build.0 = Release|Win32
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.ActiveCfg = Release|x64
{0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.Build.0 = Release|x64
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.ActiveCfg = Debug|Win32
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.Build.0 = Debug|Win32
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.ActiveCfg = Debug|x64
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.Build.0 = Debug|x64
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.ActiveCfg = Release|Win32
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.Build.0 = Release|Win32
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.ActiveCfg = Release|x64
{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.Build.0 = Release|x64
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.ActiveCfg = Debug|Win32
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.Build.0 = Debug|Win32
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.ActiveCfg = Debug|x64
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.Build.0 = Debug|x64
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.ActiveCfg = Release|Win32
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.Build.0 = Release|Win32
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.ActiveCfg = Release|x64
{62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.Build.0 = Release|x64
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.ActiveCfg = Debug|Win32
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.Build.0 = Debug|Win32
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.ActiveCfg = Debug|x64
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.Build.0 = Debug|x64
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.ActiveCfg = Release|Win32
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.Build.0 = Release|Win32
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.ActiveCfg = Release|x64
{F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.Build.0 = Release|x64
{EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.ActiveCfg = Debug|Win32
{EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.Build.0 = Debug|Win32
{EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.ActiveCfg = Debug|x64
{EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.Build.0 = Debug|x64
{EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.ActiveCfg = Release|Win32
{EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.Build.0 = Release|Win32
{EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.ActiveCfg = Release|x64
{EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.Build.0 = Release|x64
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.ActiveCfg = Debug|Win32
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.Build.0 = Debug|Win32
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.ActiveCfg = Debug|x64
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.Build.0 = Debug|x64
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.ActiveCfg = Release|Win32
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.Build.0 = Release|Win32
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.ActiveCfg = Release|x64
{B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.Build.0 = Release|x64
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.ActiveCfg = Debug|Win32
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.Build.0 = Debug|Win32
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.ActiveCfg = Debug|x64
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.Build.0 = Debug|x64
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.ActiveCfg = Release|Win32
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.Build.0 = Release|Win32
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.ActiveCfg = Release|x64
{60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal