diff --git a/CmdLineParser/CmdLineParser.cpp b/CmdLineParser/CmdLineParser.cpp index a0c80f2..f8762cd 100644 --- a/CmdLineParser/CmdLineParser.cpp +++ b/CmdLineParser/CmdLineParser.cpp @@ -176,6 +176,11 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const printf(" -l Use large pages for IO buffers\n"); printf(" -L measure latency statistics\n"); printf(" -n disable default affinity (-a)\n"); + printf(" -N specify the flush mode for memory mapped I/O\n"); + printf(" v : uses the FlushViewOfFile API\n"); + printf(" n : uses the RtlFlushNonVolatileMemory API\n"); + printf(" i : uses RtlFlushNonVolatileMemory without waiting for the flush to drain\n"); + printf(" [default: none]\n"); printf(" -o number of outstanding I/O requests per target per thread\n"); printf(" (1=synchronous I/O, unless more than 1 thread is specified with -F)\n"); printf(" [default=2]\n"); @@ -194,14 +199,16 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const printf(" manipulate a shared offset with InterlockedIncrement, which may reduce throughput,\n"); printf(" but promotes a more sequential pattern.\n"); printf(" (ignored if -r specified, -si conflicts with -T and -p)\n"); - printf(" -S[bhruw] control caching behavior [default: caching is enabled, no writethrough]\n"); + printf(" -S[bhmruw] control caching behavior [default: caching is enabled, no writethrough]\n"); printf(" non-conflicting flags may be combined in any order; ex: -Sbw, -Suw, -Swu\n"); printf(" -S equivalent to -Su\n"); printf(" -Sb enable caching (default, explicitly stated)\n"); printf(" -Sh equivalent -Suw\n"); + printf(" -Sm enable memory mapped I/O\n"); printf(" -Su disable software caching, equivalent to FILE_FLAG_NO_BUFFERING\n"); printf(" -Sr disable local caching, with remote sw caching enabled; only valid for remote filesystems\n"); - printf(" -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH\n"); + printf(" -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH or\n"); + printf(" non-temporal writes for memory mapped I/O (-Sm)\n"); printf(" -t number of threads per target (conflicts with -F)\n"); printf(" -T[K|M|G|b] starting stride between I/O operations performed on the same target by different threads\n"); printf(" [default=0] (starting offset = base file offset + (thread number * )\n"); @@ -480,6 +487,39 @@ bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan) return fOk; } +bool CmdLineParser::_ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode) +{ + assert(nullptr != arg); + assert(0 != *arg); + + bool fOk = true; + if (*(arg + 1) != '\0') + { + const char *c = arg + 1; + if (_stricmp(c, "v") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::ViewOfFile; + } + else if (_stricmp(c, "n") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::NonVolatileMemory; + } + else if (_stricmp(c, "i") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain; + } + else + { + fOk = false; + } + } + else + { + fOk = false; + } + return fOk; +} + bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch) { /* Process any command-line options */ @@ -530,6 +570,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ // this allows for conflicts to be thrown for mixed -h/-S as needed. TargetCacheMode t = TargetCacheMode::Undefined; WriteThroughMode w = WriteThroughMode::Undefined; + MemoryMappedIoMode m = MemoryMappedIoMode::Undefined; + MemoryMappedIoFlushMode f = MemoryMappedIoFlushMode::Undefined; TimeSpan timeSpan; bool bExit = false; @@ -837,6 +879,13 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ timeSpan.SetDisableAffinity(true); break; + case 'N': + if (!_ParseFlushParameter(arg, &f)) + { + fError = true; + } + break; + case 'o': //request count (1==synchronous) { int c = atoi(arg + 1); @@ -989,14 +1038,27 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ break; case 'h': if (t == TargetCacheMode::Undefined && - w == WriteThroughMode::Undefined) + w == WriteThroughMode::Undefined && + m == MemoryMappedIoMode::Undefined) { t = TargetCacheMode::DisableOSCache; w = WriteThroughMode::On; } else { - fprintf(stderr, "-Sh conflicts with earlier specification of cache/writethrough\n"); + fprintf(stderr, "-Sh conflicts with earlier specification of cache/writethrough/memory mapped\n"); + fError = true; + } + break; + case 'm': + if (m == MemoryMappedIoMode::Undefined && + t != TargetCacheMode::DisableOSCache) + { + m = MemoryMappedIoMode::On; + } + else + { + fprintf(stderr, "-Sm conflicts with earlier specification of memory mapped IO/unbuffered IO\n"); fError = true; } break; @@ -1012,13 +1074,14 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ } break; case 'u': - if (t == TargetCacheMode::Undefined) + if (t == TargetCacheMode::Undefined && + m == MemoryMappedIoMode::Undefined) { t = TargetCacheMode::DisableOSCache; } else { - fprintf(stderr, "-Su conflicts with earlier specification of cache mode\n"); + fprintf(stderr, "-Su conflicts with earlier specification of cache mode/memory mapped IO\n"); fError = true; } break; @@ -1043,7 +1106,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ // bare -S, parse loop did not advance if (!fError && idx == 1) { - if (t == TargetCacheMode::Undefined) + if (t == TargetCacheMode::Undefined && + m == MemoryMappedIoMode::Undefined) { t = TargetCacheMode::DisableOSCache; } @@ -1283,7 +1347,7 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ return false; } - // apply resultant cache/writethrough modes to the targets + // apply resultant cache/writethrough/memory mapped io modes to the targets for (auto i = vTargets.begin(); i != vTargets.end(); i++) { if (t != TargetCacheMode::Undefined) @@ -1294,6 +1358,14 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[ { i->SetWriteThroughMode(w); } + if (m != MemoryMappedIoMode::Undefined) + { + i->SetMemoryMappedIoMode(m); + } + if (f != MemoryMappedIoFlushMode::Undefined) + { + i->SetMemoryMappedIoFlushMode(f); + } } // ... and apply targets to the timespan diff --git a/CmdRequestCreator/CmdRequestCreator.cpp b/CmdRequestCreator/CmdRequestCreator.cpp index 5aa927b..d9b3eb5 100644 --- a/CmdRequestCreator/CmdRequestCreator.cpp +++ b/CmdRequestCreator/CmdRequestCreator.cpp @@ -152,6 +152,8 @@ int __cdecl main(int argc, const char* argv[]) return 1; } + TraceLoggingRegister(g_hEtwProvider); + // // call IO request generator // @@ -179,6 +181,8 @@ int __cdecl main(int argc, const char* argv[]) return 1; } + TraceLoggingUnregister(g_hEtwProvider); + if( NULL != synch.hStartEvent ) { CloseHandle(synch.hStartEvent); diff --git a/Common/CmdLineParser.h b/Common/CmdLineParser.h index 613d02f..c970913 100644 --- a/Common/CmdLineParser.h +++ b/Common/CmdLineParser.h @@ -45,6 +45,7 @@ class CmdLineParser bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile); bool _ParseETWParameter(const char *arg, Profile *pProfile); + bool _ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode ); bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan); void _DisplayUsageInfo(const char *pszFilename) const; diff --git a/Common/Common.cpp b/Common/Common.cpp index 6ebebca..ab29d5b 100644 --- a/Common/Common.cpp +++ b/Common/Common.cpp @@ -29,6 +29,10 @@ SOFTWARE. #include "Common.h" +TRACELOGGING_DEFINE_PROVIDER(g_hEtwProvider, + "Microsoft-Windows-DiskSpd", // {CA13DB84-D0A9-5145-FCA4-468DA92FDC2D} + (0xca13db84, 0xd0a9, 0x5145, 0xfc, 0xa4, 0x46, 0x8d, 0xa9, 0x2f, 0xdc, 0x2d)); + SystemInformation g_SystemInformation; UINT64 PerfTimer::GetTime() @@ -288,6 +292,28 @@ string Target::GetXml() const break; } + // MemoryMappedIoMode::Off is implied default + switch (_memoryMappedIoMode) + { + case MemoryMappedIoMode::On: + sXml += "true\n"; + break; + } + + // MemoryMappedIoFlushMode::Undefined is implied default + switch (_memoryMappedIoFlushMode) + { + case MemoryMappedIoFlushMode::ViewOfFile: + sXml += "ViewOfFile\n"; + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + sXml += "NonVolatileMemory\n"; + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + sXml += "NonVolatileMemoryNoDrain\n"; + break; + } + sXml += "\n"; if (_fZeroWriteBuffers) { @@ -854,6 +880,26 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const } } + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + if (timeSpan.GetCompletionRoutines()) + { + fprintf(stderr, "ERROR: completion routines (-x) can't be used with memory mapped IO (-Sm)\n"); + fOk = false; + } + if (target.GetCacheMode() == TargetCacheMode::DisableOSCache) + { + fprintf(stderr, "ERROR: unbuffered IO (-Su or -Sh) can't be used with memory mapped IO (-Sm)\n"); + fOk = false; + } + } + + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off && + target.GetMemoryMappedIoFlushMode() != MemoryMappedIoFlushMode::Undefined) + { + fprintf(stderr, "ERROR: memory mapped flush mode (-N) can only be specified with memory mapped IO (-Sm)\n"); + } + // 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 @@ -960,6 +1006,45 @@ BYTE* ThreadParameters::GetWriteBuffer(size_t iTarget, size_t iRequest) return pBuffer; } +bool ThreadParameters::InitializeMappedViewForTarget(Target& target, DWORD DesiredAccess) +{ + bool fOk = true; + DWORD dwProtect = PAGE_READWRITE; + + if (DesiredAccess == GENERIC_READ) + { + dwProtect = PAGE_READONLY; + } + + HANDLE hFile = CreateFileMapping(target.GetMappedViewFileHandle(), NULL, dwProtect, 0, 0, NULL); + fOk = (hFile != NULL); + if (fOk) + { + DWORD dwDesiredAccess = FILE_MAP_WRITE; + + if (DesiredAccess == GENERIC_READ) + { + dwDesiredAccess = FILE_MAP_READ; + } + + BYTE *mapView = (BYTE*) MapViewOfFile(hFile, dwDesiredAccess, 0, 0, 0); + fOk = (mapView != NULL); + if (fOk) + { + target.SetMappedView(mapView); + } + else + { + fprintf(stderr, "FATAL ERROR: Could not map view for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError()); + } + } + else + { + fprintf(stderr, "FATAL ERROR: Could not create a file mapping for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError()); + } + return fOk; +} + DWORD ThreadParameters::GetTotalRequestCount() const { DWORD cRequests = 0; @@ -977,3 +1062,47 @@ DWORD ThreadParameters::GetTotalRequestCount() const return cRequests; } + +void EtwResultParser::ParseResults(vector vResults) +{ + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_NONE, + DISKSPD_TRACE_INFO)) + { + for (size_t ullResults = 0; ullResults < vResults.size(); ullResults++) + { + const Results& results = vResults[ullResults]; + for (size_t ullThread = 0; ullThread < results.vThreadResults.size(); ullThread++) + { + const ThreadResults& threadResults = results.vThreadResults[ullThread]; + for (const auto& targetResults : threadResults.vTargetResults) + { + if (targetResults.ullReadIOCount) + { + _WriteResults(IOOperation::ReadIO, targetResults, ullThread); + } + if (targetResults.ullWriteIOCount) + { + _WriteResults(IOOperation::WriteIO, targetResults, ullThread); + } + } + } + } + } +} + +void EtwResultParser::_WriteResults(IOOperation type, const TargetResults& targetResults, size_t ullThread) +{ + UINT64 ullIOCount = (type == IOOperation::ReadIO) ? targetResults.ullReadIOCount : targetResults.ullWriteIOCount; + UINT64 ullBytesCount = (type == IOOperation::ReadIO) ? targetResults.ullReadBytesCount : targetResults.ullWriteBytesCount; + + TraceLoggingWrite(g_hEtwProvider, + "Statistics", + TraceLoggingLevel((TRACE_LEVEL_NONE)), + TraceLoggingString((type == IOOperation::ReadIO) ? "Read" : "Write", "IO Type"), + TraceLoggingUInt64(ullThread, "Thread"), + TraceLoggingUInt64(ullBytesCount, "Bytes"), + TraceLoggingUInt64(ullIOCount, "IO Count"), + TraceLoggingString(targetResults.sPath.c_str(), "Path"), + TraceLoggingUInt64(targetResults.ullFileSize, "File Size")); +} diff --git a/Common/Common.h b/Common/Common.h index 7e4b4b0..2120830 100644 --- a/Common/Common.h +++ b/Common/Common.h @@ -30,6 +30,9 @@ SOFTWARE. #pragma once #include +#include +#include +#include #include #include #include //ntdll.dll @@ -40,6 +43,8 @@ SOFTWARE. using namespace std; +TRACELOGGING_DECLARE_PROVIDER(g_hEtwProvider); + // versioning material. for simplicity in consumption, please ensure that the date string // parses via the System.Datetime constructor as follows (in Powershell): // @@ -54,7 +59,7 @@ using namespace std; #define DISKSPD_MAJOR 2 #define DISKSPD_MINOR 0 -#define DISKSPD_BUILD 20 +#define DISKSPD_BUILD 21 #define DISKSPD_QFE 0 #define DISKSPD_MAJORMINOR_VER_STR(x,y,z) #x "." #y "." #z @@ -62,7 +67,11 @@ using namespace std; #define DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_MAJORMINOR_VERSION_STRING(DISKSPD_MAJOR, DISKSPD_MINOR, DISKSPD_BUILD) #define DISKSPD_NUMERIC_VERSION_STRING DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_REVISION DISKSPD_RELEASE_TAG -#define DISKSPD_DATE_VERSION_STRING "2018/2/28" +#define DISKSPD_DATE_VERSION_STRING "2018/9/21" + +#define DISKSPD_TRACE_INFO 0x00000000 +#define DISKSPD_TRACE_RESERVED 0x00000001 +#define DISKSPD_TRACE_IO 0x00000100 typedef void (WINAPI *PRINTF)(const char*, va_list); //function used for displaying formatted data (printf style) @@ -660,6 +669,35 @@ class SystemInformation StartTime = { 0 }; } + string SystemInformation::GetText() const + { + char szBuffer[64]; // enough for 64bit mask (17ch) and timestamp + int nWritten; + string sText("System information:\n\n"); + + // identify computer which ran the test + sText += "\tcomputer name: "; + sText += sComputerName; + sText += "\n"; + + sText += "\tstart time: "; + if (StartTime.wYear) { + + nWritten = sprintf_s(szBuffer, _countof(szBuffer), + "%u/%02u/%02u %02u:%02u:%02u UTC", + StartTime.wYear, + StartTime.wMonth, + StartTime.wDay, + StartTime.wHour, + StartTime.wMinute, + StartTime.wSecond); + assert(nWritten && nWritten < _countof(szBuffer)); + sText += szBuffer; + } + + return sText; + } + string SystemInformation::GetXml() const { char szBuffer[64]; // enough for 64bit mask (17ch) and timestamp @@ -791,6 +829,25 @@ enum class WriteThroughMode { On, }; +// memory mapped IO modes +// off -> default +// on -> (-Sm or -Smw) +enum class MemoryMappedIoMode { + Undefined = 0, + Off, + On, +}; + +// memory mapped IO flush modes +// off / Undefined -> default +// on -> (-Sm or -Smw) +enum class MemoryMappedIoFlushMode { + Undefined = 0, + ViewOfFile, + NonVolatileMemory, + NonVolatileMemoryNoDrain, +}; + class ThreadTarget { public: @@ -829,6 +886,9 @@ class Target _fInterlockedSequential(false), _cacheMode(TargetCacheMode::Cached), _writeThroughMode(WriteThroughMode::Off), + _memoryMappedIoMode(MemoryMappedIoMode::Off), + _memoryMappedIoNvToken(nullptr), + _memoryMappedIoFlushMode(MemoryMappedIoFlushMode::Undefined), _fZeroWriteBuffers(false), _dwThreadsPerFile(1), _ullThreadStride(0), @@ -845,6 +905,8 @@ class Target _fRandomAccessHint(false), _fTemporaryFileHint(false), _fUseLargePages(false), + _mappedViewFileHandle(INVALID_HANDLE_VALUE), + _mappedView(NULL), _ioPriorityHint(IoPriorityHintNormal), _ulWeight(1), _dwThroughputBytesPerMillisecond(0), @@ -899,6 +961,15 @@ class Target void SetWriteThroughMode(WriteThroughMode writeThroughMode ) { _writeThroughMode = writeThroughMode; } WriteThroughMode GetWriteThroughMode( ) const { return _writeThroughMode; } + void SetMemoryMappedIoMode(MemoryMappedIoMode memoryMappedIoMode ) { _memoryMappedIoMode = memoryMappedIoMode; } + MemoryMappedIoMode GetMemoryMappedIoMode( ) const { return _memoryMappedIoMode; } + + void SetMemoryMappedIoNvToken(PVOID memoryMappedIoNvToken) { _memoryMappedIoNvToken = memoryMappedIoNvToken; } + PVOID GetMemoryMappedIoNvToken() const { return _memoryMappedIoNvToken; } + + void SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode memoryMappedIoFlushMode) { _memoryMappedIoFlushMode = memoryMappedIoFlushMode; } + MemoryMappedIoFlushMode GetMemoryMappedIoFlushMode() const { return _memoryMappedIoFlushMode; } + void SetZeroWriteBuffers(bool fBool) { _fZeroWriteBuffers = fBool; } bool GetZeroWriteBuffers() const { return _fZeroWriteBuffers; } @@ -944,6 +1015,12 @@ class Target void SetThreadStrideInBytes(UINT64 ullThreadStride) { _ullThreadStride = ullThreadStride; } UINT64 GetThreadStrideInBytes() const { return _ullThreadStride; } + void SetMappedViewFileHandle(HANDLE FileHandle) { _mappedViewFileHandle = FileHandle; } + HANDLE GetMappedViewFileHandle() const { return _mappedViewFileHandle; } + + void SetMappedView(BYTE *MappedView) { _mappedView = MappedView; } + BYTE* GetMappedView() const { return _mappedView; } + void SetIOPriorityHint(PRIORITY_HINT _hint) { assert(_hint < MaximumIoPriorityHintType); @@ -1024,6 +1101,9 @@ class Target TargetCacheMode _cacheMode; WriteThroughMode _writeThroughMode; + MemoryMappedIoMode _memoryMappedIoMode; + MemoryMappedIoFlushMode _memoryMappedIoFlushMode; + PVOID _memoryMappedIoNvToken; bool _fZeroWriteBuffers; DWORD _dwThreadsPerFile; UINT64 _ullThreadStride; @@ -1050,6 +1130,9 @@ class Target 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 + HANDLE _mappedViewFileHandle; + BYTE *_mappedView; + PRIORITY_HINT _ioPriorityHint; UINT32 _ulWeight; @@ -1305,7 +1388,8 @@ class IORequest _ullStartTime(0), _ulRequestIndex(0xFFFFFFFF), _ullTotalWeight(0), - _fEqualWeights(true) + _fEqualWeights(true), + _ActivityId() { memset(&_overlapped, 0, sizeof(OVERLAPPED)); _overlapped.Offset = 0xFFFFFFFF; @@ -1367,6 +1451,9 @@ class IORequest void SetRequestIndex(UINT32 ulRequestIndex) { _ulRequestIndex = ulRequestIndex; } UINT32 GetRequestIndex() const { return _ulRequestIndex; } + void SetActivityId(GUID ActivityId) { _ActivityId = ActivityId; } + GUID GetActivityId() const { return _ActivityId; } + private: OVERLAPPED _overlapped; vector _vTargets; @@ -1378,8 +1465,17 @@ class IORequest IOOperation _ioType; UINT64 _ullStartTime; UINT32 _ulRequestIndex; + GUID _ActivityId; }; +typedef struct _ACTIVITY_ID { + UINT32 Thread; + UINT32 Reserved; + UINT64 Count; +} ACTIVITY_ID; + +C_ASSERT(sizeof(ACTIVITY_ID) == sizeof(GUID)); + class ThreadParameters { public: @@ -1439,9 +1535,24 @@ class ThreadParameters BYTE* GetReadBuffer(size_t iTarget, size_t iRequest); BYTE* GetWriteBuffer(size_t iTarget, size_t iRequest); DWORD GetTotalRequestCount() const; + bool InitializeMappedViewForTarget(Target& target, DWORD DesiredAccess); + + GUID NextActivityId() + { + GUID ActivityId; + ACTIVITY_ID* ActivityGuid = (ACTIVITY_ID*)&ActivityId; + + ActivityGuid->Thread = ulThreadNo; + ActivityGuid->Reserved = 0; + // The count is byte swapped so it's understandable in a trace. + ActivityGuid->Count = _byteswap_uint64(++_ullActivityCount); + + return ActivityId; + } private: ThreadParameters(const ThreadParameters& T); + UINT64 _ullActivityCount; }; class IResultParser @@ -1449,3 +1560,12 @@ class IResultParser public: virtual string ParseResults(Profile& profile, const SystemInformation& system, vector vResults) = 0; }; + +class EtwResultParser +{ +public: + static void ParseResults(vector vResults); + +private: + static void _WriteResults(IOOperation type, const TargetResults& targetResults, size_t uThread); +}; diff --git a/Common/ResultParser.h b/Common/ResultParser.h index 45538f4..560448e 100644 --- a/Common/ResultParser.h +++ b/Common/ResultParser.h @@ -46,6 +46,7 @@ class ResultParser : public IResultParser void _DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters); void _Print(const char *format, ...); void _PrintProfile(const Profile& profile); + void _PrintSystemInfo(const SystemInformation& system); void _PrintCpuUtilization(const Results& results, const SystemInformation& system); enum class _SectionEnum {TOTAL, READ, WRITE}; void _PrintSectionFieldNames(const TimeSpan& timeSpan); diff --git a/Common/xmlresultparser.h b/Common/XmlResultParser.h similarity index 100% rename from Common/xmlresultparser.h rename to Common/XmlResultParser.h diff --git a/DiskSpd_Documentation.docx b/DiskSpd_Documentation.docx deleted file mode 100644 index 9cfd18e..0000000 Binary files a/DiskSpd_Documentation.docx and /dev/null differ diff --git a/DiskSpd_Documentation.pdf b/DiskSpd_Documentation.pdf deleted file mode 100644 index 2180fb3..0000000 Binary files a/DiskSpd_Documentation.pdf and /dev/null differ diff --git a/IORequestGenerator/IORequestGenerator.cpp b/IORequestGenerator/IORequestGenerator.cpp index 73ad128..abecb6a 100644 --- a/IORequestGenerator/IORequestGenerator.cpp +++ b/IORequestGenerator/IORequestGenerator.cpp @@ -50,6 +50,11 @@ SOFTWARE. #include "ThroughputMeter.h" #include "OverlappedQueue.h" +// Flags for RtlFlushNonVolatileMemory +#ifndef FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN +#define FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN (0x00000001) +#endif + /*****************************************************************************/ // gets size of a dynamic volume, return zero on failure // @@ -412,6 +417,18 @@ static BOOL volatile g_bRun; //used for letting threads know typedef NTSTATUS (__stdcall *NtQuerySysInfo)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NtQuerySysInfo g_pfnNtQuerySysInfo; +typedef VOID (__stdcall *RtlCopyMemNonTemporal)(VOID UNALIGNED *, VOID UNALIGNED *, SIZE_T); +static RtlCopyMemNonTemporal g_pfnRtlCopyMemoryNonTemporal; + +typedef NTSTATUS (__stdcall *RtlFlushNvMemory)(PVOID, PVOID, SIZE_T, ULONG); +static RtlFlushNvMemory g_pfnRtlFlushNonVolatileMemory; + +typedef NTSTATUS(__stdcall *RtlGetNvToken)(PVOID, SIZE_T, PVOID *); +static RtlGetNvToken g_pfnRtlGetNonVolatileToken; + +typedef NTSTATUS(__stdcall *RtlFreeNvToken)(PVOID); +static RtlFreeNvToken g_pfnRtlFreeNonVolatileToken; + static PRINTF g_pfnPrintOut = nullptr; static PRINTF g_pfnPrintError = nullptr; static PRINTF g_pfnPrintVerbose = nullptr; @@ -550,6 +567,11 @@ bool IORequestGenerator::_LoadDLLs() return false; } + g_pfnRtlCopyMemoryNonTemporal = (RtlCopyMemNonTemporal)GetProcAddress(_hNTDLL, "RtlCopyMemoryNonTemporal"); + g_pfnRtlFlushNonVolatileMemory = (RtlFlushNvMemory)GetProcAddress(_hNTDLL, "RtlFlushNonVolatileMemory"); + g_pfnRtlGetNonVolatileToken = (RtlGetNvToken)GetProcAddress(_hNTDLL, "RtlGetNonVolatileToken"); + g_pfnRtlFreeNonVolatileToken = (RtlFreeNvToken)GetProcAddress(_hNTDLL, "RtlFreeNonVolatileToken"); + return true; } @@ -716,7 +738,7 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy size_t iTarget = pTarget - &p->vTargets[0]; UINT32 iRequest = pIORequest->GetRequestIndex(); LARGE_INTEGER li; - bool rslt; + BOOL rslt = true; li.LowPart = pOverlapped->Offset; li.HighPart = pOverlapped->OffsetHigh; @@ -726,15 +748,30 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy pOverlapped->Offset = li.LowPart; pOverlapped->OffsetHigh = li.HighPart; - printfv(p->pProfile->GetVerbose(), "t[%u:%u] new I/O op at %I64u (starting in block: %I64u)\n", - p->ulThreadNo, - iTarget, - li.QuadPart, - li.QuadPart / pTarget->GetBlockSizeInBytes()); - IOOperation readOrWrite = DecideIo(p->pRand, pTarget->GetWriteRatio()); pIORequest->SetIoType(readOrWrite); + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_VERBOSE, + DISKSPD_TRACE_IO)) + { + GUID ActivityId = p->NextActivityId(); + pIORequest->SetActivityId(ActivityId); + + TraceLoggingWriteActivity(g_hEtwProvider, + "DiskSpd IO", + &ActivityId, + NULL, + TraceLoggingKeyword(DISKSPD_TRACE_IO), + TraceLoggingOpcode(EVENT_TRACE_TYPE_START), + TraceLoggingLevel(TRACE_LEVEL_VERBOSE), + TraceLoggingUInt32(p->ulThreadNo, "Thread"), + TraceLoggingString(readOrWrite == IOOperation::ReadIO ? "Read" : "Write", "IO Type"), + TraceLoggingUInt64(iTarget, "Target"), + TraceLoggingInt32(pTarget->GetBlockSizeInBytes(), "Block Size"), + TraceLoggingInt64(li.QuadPart, "Offset")); + } + if (p->pTimeSpan->GetMeasureLatency()) { pIORequest->SetStartTime(PerfTimer::GetTime()); @@ -742,24 +779,67 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy if (readOrWrite == IOOperation::ReadIO) { - if (useCompletionRoutines) + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) { - rslt = ReadFileEx(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On ) + { + g_pfnRtlCopyMemoryNonTemporal(p->GetReadBuffer(iTarget, iRequest), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + } + else + { + memcpy(p->GetReadBuffer(iTarget, iRequest), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + } + *pdwBytesTransferred = pTarget->GetBlockSizeInBytes(); } else { - rslt = ReadFile(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + if (useCompletionRoutines) + { + rslt = ReadFileEx(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + else + { + rslt = ReadFile(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + } } } else { - if (useCompletionRoutines) + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) { - rslt = WriteFileEx(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On) + { + g_pfnRtlCopyMemoryNonTemporal(pTarget->GetMappedView() + li.QuadPart, p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes()); + } + else + { + memcpy(pTarget->GetMappedView() + li.QuadPart, p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes()); + + switch (pTarget->GetMemoryMappedIoFlushMode()) + { + case MemoryMappedIoFlushMode::ViewOfFile: + FlushViewOfFile(pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + g_pfnRtlFlushNonVolatileMemory(pTarget->GetMemoryMappedIoNvToken(), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes(), 0); + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + g_pfnRtlFlushNonVolatileMemory(pTarget->GetMemoryMappedIoNvToken(), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes(), FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN); + break; + } + } + *pdwBytesTransferred = pTarget->GetBlockSizeInBytes(); } else { - rslt = WriteFile(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + if (useCompletionRoutines) + { + rslt = WriteFileEx(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + else + { + rslt = WriteFile(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + } } } @@ -768,7 +848,7 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy p->vThroughputMeters[iTarget].Adjust(pTarget->GetBlockSizeInBytes()); } - return rslt; + return (rslt) ? true : false; } static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred) @@ -776,6 +856,21 @@ static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytes Target *pTarget = pIORequest->GetCurrentTarget(); size_t iTarget = pTarget - &p->vTargets[0]; + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_VERBOSE, + DISKSPD_TRACE_IO)) + { + GUID ActivityId = pIORequest->GetActivityId(); + + TraceLoggingWriteActivity(g_hEtwProvider, + "DiskSpd IO", + &ActivityId, + NULL, + TraceLoggingKeyword(DISKSPD_TRACE_IO), + TraceLoggingOpcode(EVENT_TRACE_TYPE_STOP), + TraceLoggingLevel(TRACE_LEVEL_VERBOSE)); + } + //check if I/O transferred all of the requested bytes if (dwBytesTransferred != pTarget->GetBlockSizeInBytes()) { @@ -815,35 +910,47 @@ static bool doWorkUsingSynchronousIO(ThreadParameters *p) bool fOk = true; BOOL rslt = FALSE; DWORD dwBytesTransferred; - IORequest *pIORequest = &p->vIORequest[0]; + size_t cIORequests = p->vIORequest.size(); while(g_bRun && !g_bThreadError) { - Target *pTarget = pIORequest->GetNextTarget(); - - if (p->vThroughputMeters.size() != 0) + DWORD dwMinSleepTime = ~((DWORD)0); + for (size_t i = 0; i < cIORequests; i++) { - size_t iTarget = pTarget - &p->vTargets[0]; - ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[iTarget]; - DWORD dwSleepTime = pThroughputMeter->GetSleepTime(); - if (pThroughputMeter->IsRunning() && dwSleepTime > 0) + IORequest *pIORequest = &p->vIORequest[i]; + Target *pTarget = pIORequest->GetNextTarget(); + + if (p->vThroughputMeters.size() != 0) { - Sleep(dwSleepTime); - continue; + size_t iTarget = pTarget - &p->vTargets[0]; + ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[iTarget]; + + DWORD dwSleepTime = pThroughputMeter->GetSleepTime(); + dwMinSleepTime = min(dwMinSleepTime, dwSleepTime); + if (pThroughputMeter->IsRunning() && dwSleepTime > 0) + { + continue; + } + } + + rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false); + + if (!rslt) + { + PrintError("t[%u] error during %s error code: %u)\n", (UINT32)i, (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; } + + completeIO(p, pIORequest, dwBytesTransferred); } - rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false); - - if (!rslt) + // if no IOs were issued, wait for the next scheduling time + if (dwMinSleepTime != ~((DWORD)0) && dwMinSleepTime != 0) { - PrintError("t[%u] error during %s error code: %u)\n", 0, (pIORequest->GetIoType()== IOOperation::ReadIO ? "read" : "write"), GetLastError()); - fOk = false; - goto cleanup; + Sleep(dwMinSleepTime); } - completeIO(p, pIORequest, dwBytesTransferred); - assert(!g_bError); // at this point we shouldn't be seeing initialization error } @@ -900,7 +1007,7 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion } } - rslt = issueNextIO(p, pIORequest, NULL, false); + rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false); if (!rslt && GetLastError() != ERROR_IO_PENDING) { @@ -909,6 +1016,12 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion fOk = false; goto cleanup; } + + if (rslt && pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + completeIO(p, pIORequest, dwBytesTransferred); + overlappedQueue.Add(pReadyOverlapped); + } } // if no IOs are in flight, wait for the next scheduling time @@ -1082,6 +1195,8 @@ struct UniqueTarget { DWORD WINAPI threadFunc(LPVOID cookie) { bool fOk = true; + bool fAnyMappedIo = false; + bool fAllMappedIo = true; ThreadParameters *p = reinterpret_cast(cookie); HANDLE hCompletionPort = nullptr; @@ -1159,6 +1274,12 @@ DWORD WINAPI threadFunc(LPVOID cookie) //check if it is a physical drive if ('#' == *filename && NULL != *(filename + 1)) { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + PrintError("Memory mapped I/O is not supported on physical drives\n"); + fOk = false; + goto cleanup; + } UINT32 nDriveNo = (UINT32)atoi(filename + 1); fPhysical = true; sprintf_s(physFN, 32, "\\\\.\\PhysicalDrive%u", nDriveNo); @@ -1168,6 +1289,12 @@ DWORD WINAPI threadFunc(LPVOID cookie) //check if it is a partition if (!fPhysical && NULL != *(filename + 1) && NULL == *(filename + 2) && isalpha((unsigned char)filename[0]) && ':' == filename[1]) { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + PrintError("Memory mapped I/O is not supported on partitions\n"); + fOk = false; + goto cleanup; + } fPartition = true; sprintf_s(physFN, 32, "\\\\.\\%c:", filename[0]); @@ -1196,6 +1323,16 @@ DWORD WINAPI threadFunc(LPVOID cookie) dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; } + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + fAnyMappedIo = true; + } + else + { + fAllMappedIo = false; + } + HANDLE hFile; UniqueTarget ut; ut.path = sPath; @@ -1347,10 +1484,55 @@ DWORD WINAPI threadFunc(LPVOID cookie) // allocate memory for a data buffer if (!p->AllocateAndFillBufferForTarget(*pTarget)) { - PrintError("FATAL ERROR: Could not allocate a buffer bytes for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + PrintError("ERROR: Could not allocate a buffer for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); fOk = false; goto cleanup; } + + // initialize memory mapped views of files + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + NTSTATUS status; + PVOID nvToken; + + pTarget->SetMappedViewFileHandle(hFile); + if (!p->InitializeMappedViewForTarget(*pTarget, dwDesiredAccess)) + { + PrintError("ERROR: Could not map view for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On && nullptr == g_pfnRtlCopyMemoryNonTemporal) + { + PrintError("ERROR: Windows runtime environment does not support the non-temporal memory copy API for target '%s'.\n", pTarget->GetPath().c_str()); + fOk = false; + goto cleanup; + } + + if ((pTarget->GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemory) || (pTarget->GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain)) + { + // RtlGetNonVolatileToken() works only on DAX enabled PMEM devices. + if (g_pfnRtlGetNonVolatileToken != nullptr && g_pfnRtlFreeNonVolatileToken != nullptr) + { + status = g_pfnRtlGetNonVolatileToken(pTarget->GetMappedView(), (SIZE_T) pTarget->GetFileSize(), &nvToken); + if (!NT_SUCCESS(status)) + { + PrintError("ERROR: Could not get non-volatile token for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + pTarget->SetMemoryMappedIoNvToken(nvToken); + } + else + { + PrintError("ERROR: Windows runtime environment does not support the non-volatile memory flushing APIs for target '%s'.\n", pTarget->GetPath().c_str()); + fOk = false; + goto cleanup; + } + } + } + iTarget++; } @@ -1469,11 +1651,11 @@ DWORD WINAPI threadFunc(LPVOID cookie) } //FUTURE EXTENSION: enable asynchronous I/O even if only 1 outstanding I/O per file (requires another parameter) - if (cIORequests == 1) + if (cIORequests == 1 || fAllMappedIo) { //synchronous IO - no setup needed } - else if (p->pTimeSpan->GetCompletionRoutines()) + else if (p->pTimeSpan->GetCompletionRoutines() && !fAnyMappedIo) { //in case of completion routines hEvent field is not used, //so we can use it to pass a pointer to the thread parameters @@ -1521,7 +1703,7 @@ DWORD WINAPI threadFunc(LPVOID cookie) } //error handling and memory freeing is done in doWorkUsingIOCompletionPorts and doWorkUsingCompletionRoutines - if (cIORequests == 1) + if (cIORequests == 1 || fAllMappedIo) { // use synchronous IO (it will also clse the event) if (!doWorkUsingSynchronousIO(p)) @@ -1530,7 +1712,7 @@ DWORD WINAPI threadFunc(LPVOID cookie) goto cleanup; } } - else if (!p->pTimeSpan->GetCompletionRoutines()) + else if (!p->pTimeSpan->GetCompletionRoutines() || fAnyMappedIo) { // use IO Completion Ports (it will also close the I/O completion port) if (!doWorkUsingIOCompletionPorts(p, hCompletionPort)) @@ -1569,6 +1751,16 @@ DWORD WINAPI threadFunc(LPVOID cookie) } } + // free NV tokens + for (auto i = p->vTargets.begin(); i != p->vTargets.end(); i++) + { + if (i->GetMemoryMappedIoNvToken() != nullptr && g_pfnRtlFreeNonVolatileToken != nullptr) + { + g_pfnRtlFreeNonVolatileToken(i->GetMemoryMappedIoNvToken()); + i->SetMemoryMappedIoNvToken(nullptr); + } + } + // close files for (auto i = vhUniqueHandles.begin(); i != vhUniqueHandles.end(); i++) { @@ -1924,6 +2116,7 @@ bool IORequestGenerator::GenerateRequests(Profile& profile, IResultParser& resul // TODO: show results only for timespans that succeeded SystemInformation system; + EtwResultParser::ParseResults(vResults); string sResults = resultParser.ParseResults(profile, system, vResults); print("%s", sResults.c_str()); } @@ -2255,6 +2448,9 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co // if (timeSpan.GetWarmup() > 0) { + TraceLoggingActivity WarmActivity; + TraceLoggingWriteStart(WarmActivity, "Warm Up"); + if (bSynchStop) { assert(NULL != pSynch->hStopEvent); @@ -2271,6 +2467,8 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co { Sleep(1000 * timeSpan.GetWarmup()); } + + TraceLoggingWriteStop(WarmActivity, "Warm Up"); } if (!bBreak) // proceed only if user didn't break the test @@ -2324,6 +2522,9 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co return false; } + TraceLoggingActivity RunActivity; + TraceLoggingWriteStart(RunActivity, "Run Time"); + //get cycle count (it will be used to calculate actual work time) ullStartTime = PerfTimer::GetTime(); @@ -2356,6 +2557,8 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co //get cycle count and perf counters ullTimeDiff = PerfTimer::GetTime() - ullStartTime; + TraceLoggingWriteStop(RunActivity, "Run Time"); + if (_GetSystemPerfInfo(&vPerfDone[0], g_SystemInformation.processorTopology._ulProcCount) == FALSE) { PrintError("Error getting performance counters\n"); @@ -2395,6 +2598,9 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co printfv(profile.GetVerbose(), "starting cool down...\n"); if ((timeSpan.GetCooldown() > 0) && !bBreak) { + TraceLoggingActivity CoolActivity; + TraceLoggingWriteStart(CoolActivity, "Cool Down"); + if (bSynchStop) { assert(NULL != pSynch->hStopEvent); @@ -2411,6 +2617,8 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co { Sleep(1000 * timeSpan.GetCooldown()); } + + TraceLoggingWriteStop(CoolActivity, "Cool Down"); } printfv(profile.GetVerbose(), "finished test...\n"); diff --git a/process-diskspd.ps1 b/Process-DiskSpd.ps1 similarity index 100% rename from process-diskspd.ps1 rename to Process-DiskSpd.ps1 diff --git a/README.md b/README.md index 5555311..13104cc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ DiskSpd DiskSpd is a storage performance tool from the Windows, Windows Server and Cloud Server Infrastructure engineering teams at Microsoft. Please visit for updated documentation. The latest update to DiskSpd can be downloaded from . - In addition to the tool itself, this repository hosts measurement frameworks which utilize DiskSpd. The initial example is [VM Fleet](https://github.com/Microsoft/diskspd/blob/master/Frameworks/VMFleet) that was used for the Windows Server 2016 Hyper-Converged Storage Spaces Direct work. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. @@ -13,6 +12,15 @@ What's New? ## DISKSPD ## +DISKSPD 2.0.21a 9/21/2018 + +* Added support for memory mapped I/O: + * New `-Sm` option to enable memory mapped I/O + * New `-N` option to specify flush options for memory mapped I/O +* Added support for providing Event Tracing for Windows (ETW) events +* Included a Windows Performance Recorder (WPR) profile to enable ETW tracing +* Added system information to the ResultParser output + DISKSPD 2.0.20a 2/28/2018 * Changes that may require rebaselining of results: diff --git a/ResultParser/ResultParser.cpp b/ResultParser/ResultParser.cpp index 448bd9d..b1872d1 100644 --- a/ResultParser/ResultParser.cpp +++ b/ResultParser/ResultParser.cpp @@ -254,6 +254,23 @@ void ResultParser::_PrintTarget(const Target &target, bool fUseThreadsPerFile, b _Print("\t\tusing hardware write cache, writethrough off\n"); } + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + _Print("\t\tmemory mapped I/O enabled"); + switch(target.GetMemoryMappedIoFlushMode()) + { + case MemoryMappedIoFlushMode::ViewOfFile: + _Print(", flush mode: FlushViewOfFile"); + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + _Print(", flush mode: FlushNonVolatileMemory"); + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + _Print(", flush mode: FlushNonVolatileMemory with no drain"); + break; + } + _Print("\n"); + } if (target.GetZeroWriteBuffers()) { @@ -440,6 +457,11 @@ void ResultParser::_PrintProfile(const Profile& profile) } } +void ResultParser::_PrintSystemInfo(const SystemInformation& system) +{ + _Print(system.GetText().c_str()); +} + void ResultParser::_PrintCpuUtilization(const Results& results, const SystemInformation& system) { size_t ulProcCount = results.vSystemProcessorPerfInfo.size(); @@ -824,12 +846,10 @@ void ResultParser::_PrintLatencyChart(const Histogram& readLatencyHistogr string ResultParser::ParseResults(Profile& profile, const SystemInformation& system, vector vResults) { - // TODO: print text representation of system information (see xml parser) - UNREFERENCED_PARAMETER(system); - _sResult.clear(); _PrintProfile(profile); + _PrintSystemInfo(system); for (size_t iResult = 0; iResult < vResults.size(); iResult++) { diff --git a/UnitTests/cmdlineparser/CmdLineParser.UnitTests.cpp b/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp similarity index 93% rename from UnitTests/cmdlineparser/CmdLineParser.UnitTests.cpp rename to UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp index 21ebfc6..b1d3a7e 100644 --- a/UnitTests/cmdlineparser/CmdLineParser.UnitTests.cpp +++ b/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp @@ -438,6 +438,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); VERIFY_IS_TRUE(t.GetCreateFile() == false); @@ -465,6 +467,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -543,6 +547,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -616,6 +622,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -720,6 +728,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -811,6 +821,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -854,6 +866,13 @@ namespace UnitTests VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); } + // conflict mu + { + Profile profile; + const char *argv[] = { "foo", "-Smu", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + // conflict with -h/-Sb, either order { Profile profile; @@ -867,6 +886,13 @@ namespace UnitTests VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); } + // conflict with -h/-Sm + { + Profile profile; + const char *argv[] = { "foo", "-Sm", "-h", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + // multiple with -h/-Suw, either order { Profile profile; @@ -894,6 +920,13 @@ namespace UnitTests VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); } + // multiple with -Sm/-Sm + { + Profile profile; + const char *argv[] = { "foo", "-Sm", "-Sm", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + // invalid option { Profile profile; @@ -956,6 +989,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1039,6 +1074,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1111,6 +1148,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1183,6 +1222,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableLocalCache); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1255,6 +1296,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1273,6 +1316,118 @@ namespace UnitTests VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); } + void CmdLineParserUnitTests::VerifyParseCmdLineMappedIO(Profile &profile, MemoryMappedIoFlushMode FlushMode) + { + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetUseRandomAccessPattern() == false); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == FlushMode); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineMappedIO() + { + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::Undefined); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Nv", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Nv testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::ViewOfFile); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Nn", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Nn testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::NonVolatileMemory); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Ni", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Ni testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + } + } + void CmdLineParserUnitTests::TestParseCmdLineUseCompletionRoutines() { CmdLineParser p; @@ -1327,6 +1482,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1399,6 +1556,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1471,6 +1630,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1543,6 +1704,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1615,6 +1778,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1687,6 +1852,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == true); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1759,6 +1926,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1831,6 +2000,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1903,6 +2074,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -1975,6 +2148,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2047,6 +2222,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2119,6 +2296,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2191,6 +2370,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2263,6 +2444,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)23); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), (567 * 1024)); @@ -2335,6 +2518,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2407,6 +2592,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2479,6 +2666,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2551,6 +2740,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2623,6 +2814,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2695,6 +2888,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2767,6 +2962,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2839,6 +3036,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2911,6 +3110,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -2983,6 +3184,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3055,6 +3258,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3127,6 +3332,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3199,6 +3406,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3272,6 +3481,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3344,6 +3555,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == true); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3418,6 +3631,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3566,6 +3781,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3638,6 +3855,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -3710,6 +3929,8 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); diff --git a/UnitTests/cmdlineparser/CmdLineParser.UnitTests.h b/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h similarity index 97% rename from UnitTests/cmdlineparser/CmdLineParser.UnitTests.h rename to UnitTests/CmdLineParser/CmdLineParser.UnitTests.h index f450669..87516f0 100644 --- a/UnitTests/cmdlineparser/CmdLineParser.UnitTests.h +++ b/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h @@ -43,6 +43,7 @@ namespace UnitTests { private: void VerifyParseCmdLineDisableAllCache(Profile &profile); + void VerifyParseCmdLineMappedIO(Profile &profile, MemoryMappedIoFlushMode FlushMode); void VerifyParseCmdLineAccessHints(Profile &profile, bool RandomAccess, bool SequentialScan, bool TemporaryFile); public: @@ -68,6 +69,7 @@ namespace UnitTests TEST_METHOD(TestParseCmdLineDisableOSCache); TEST_METHOD(TestParseCmdLineDisableLocalCache); TEST_METHOD(TestParseCmdLineBufferedWriteThrough); + TEST_METHOD(TestParseCmdLineMappedIO); TEST_METHOD(TestParseCmdLineConflictingCacheModes); TEST_METHOD(TestParseCmdLineUseCompletionRoutines); TEST_METHOD(TestParseCmdLineRandSeed); diff --git a/UnitTests/cmdlineparser/CmdLineParser.rc b/UnitTests/CmdLineParser/CmdLineParser.rc similarity index 100% rename from UnitTests/cmdlineparser/CmdLineParser.rc rename to UnitTests/CmdLineParser/CmdLineParser.rc diff --git a/UnitTests/cmdlineparser/stdafx.h b/UnitTests/CmdLineParser/stdafx.h similarity index 100% rename from UnitTests/cmdlineparser/stdafx.h rename to UnitTests/CmdLineParser/stdafx.h diff --git a/UnitTests/Common/Common.UnitTests.cpp b/UnitTests/Common/Common.UnitTests.cpp index 71d77e1..9469aea 100644 --- a/UnitTests/Common/Common.UnitTests.cpp +++ b/UnitTests/Common/Common.UnitTests.cpp @@ -749,6 +749,136 @@ namespace UnitTests "\n"); } + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIo() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + string sXml = target.GetXml(); + VERIFY_IS_TRUE(sXml == "\n" + "\n" + "65536\n" + "0\n" + "false\n" + "false\n" + "false\n" + "false\n" + "true\n" + "\n" + "sequential\n" + "\n" + "false\n" + "65536\n" + "false\n" + "0\n" + "0\n" + "2\n" + "0\n" + "0\n" + "1\n" + "3\n" + "1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeViewOfFile() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + string sXml = target.GetXml(); + VERIFY_IS_TRUE(sXml == "\n" + "\n" + "65536\n" + "0\n" + "false\n" + "false\n" + "false\n" + "false\n" + "true\n" + "ViewOfFile\n" + "\n" + "sequential\n" + "\n" + "false\n" + "65536\n" + "false\n" + "0\n" + "0\n" + "2\n" + "0\n" + "0\n" + "1\n" + "3\n" + "1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemory() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + string sXml = target.GetXml(); + VERIFY_IS_TRUE(sXml == "\n" + "\n" + "65536\n" + "0\n" + "false\n" + "false\n" + "false\n" + "false\n" + "true\n" + "NonVolatileMemory\n" + "\n" + "sequential\n" + "\n" + "false\n" + "65536\n" + "false\n" + "0\n" + "0\n" + "2\n" + "0\n" + "0\n" + "1\n" + "3\n" + "1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemoryNoDrain() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + string sXml = target.GetXml(); + VERIFY_IS_TRUE(sXml == "\n" + "\n" + "65536\n" + "0\n" + "false\n" + "false\n" + "false\n" + "false\n" + "true\n" + "NonVolatileMemoryNoDrain\n" + "\n" + "sequential\n" + "\n" + "false\n" + "65536\n" + "false\n" + "0\n" + "0\n" + "2\n" + "0\n" + "0\n" + "1\n" + "3\n" + "1\n" + "\n"); + } + void TargetUnitTests::Test_TargetGetXmlRandomAccessHint() { Target target; diff --git a/UnitTests/Common/Common.UnitTests.h b/UnitTests/Common/Common.UnitTests.h index 1e4497a..f4119ab 100644 --- a/UnitTests/Common/Common.UnitTests.h +++ b/UnitTests/Common/Common.UnitTests.h @@ -100,6 +100,10 @@ namespace UnitTests TEST_METHOD(Test_TargetGetXmlDisableLocalCache); TEST_METHOD(Test_TargetGetXmlDisableOSCache); TEST_METHOD(Test_TargetGetXmlBufferedWriteThrough); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIo); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeViewOfFile); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemory); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemoryNoDrain); TEST_METHOD(Test_TargetGetXmlRandomAccessHint); TEST_METHOD(Test_TargetGetXmlSequentialScanHint); TEST_METHOD(Test_TargetGetXmlCombinedAccessHint); diff --git a/UnitTests/ResultParser/ResultParser.UnitTests.cpp b/UnitTests/ResultParser/ResultParser.UnitTests.cpp index f2eb925..a646679 100644 --- a/UnitTests/ResultParser/ResultParser.UnitTests.cpp +++ b/UnitTests/ResultParser/ResultParser.UnitTests.cpp @@ -91,6 +91,7 @@ namespace UnitTests // to verify a static null as anything else. SystemInformation system; system.sComputerName.clear(); + system.ResetTime(); system.processorTopology._ulProcCount = 1; system.processorTopology._ulActiveProcCount = 1; system.processorTopology._vProcessorGroupInformation[0]._maximumProcessorCount = 1; @@ -117,7 +118,9 @@ namespace UnitTests "\tgathering IOPS at intervals of 1000ms\n" "\trandom seed: 0\n" "\n" - "\n" + "System information:\n\n" + "\tcomputer name: \n" + "\tstart time: \n" "\n" "Results for timespan 1:\n" "*******************************************************************************\n" @@ -306,6 +309,86 @@ namespace UnitTests VERIFY_IS_TRUE(parser._sResult == pszExpectedResult); parser._sResult = ""; + target.SetCacheMode(TargetCacheMode::Cached); + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled\n" + "\t\twrite buffer size: 12341234\n" + "\t\twrite buffer source: 'x:\\foo\\bar.dat'\n" + "\t\tperforming read test\n" + "\t\tblock size: 65536\n" + "\t\tusing random I/O (alignment: 65536)\n" + "\t\tnumber of outstanding I/O operations: 2\n" + "\t\tthread stride size: 0\n" + "\t\tIO priority: normal\n"; + VERIFY_IS_TRUE(parser._sResult == pszExpectedResult); + + parser._sResult = ""; + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushViewOfFile\n" + "\t\twrite buffer size: 12341234\n" + "\t\twrite buffer source: 'x:\\foo\\bar.dat'\n" + "\t\tperforming read test\n" + "\t\tblock size: 65536\n" + "\t\tusing random I/O (alignment: 65536)\n" + "\t\tnumber of outstanding I/O operations: 2\n" + "\t\tthread stride size: 0\n" + "\t\tIO priority: normal\n"; + VERIFY_IS_TRUE(parser._sResult == pszExpectedResult); + + parser._sResult = ""; + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushNonVolatileMemory\n" + "\t\twrite buffer size: 12341234\n" + "\t\twrite buffer source: 'x:\\foo\\bar.dat'\n" + "\t\tperforming read test\n" + "\t\tblock size: 65536\n" + "\t\tusing random I/O (alignment: 65536)\n" + "\t\tnumber of outstanding I/O operations: 2\n" + "\t\tthread stride size: 0\n" + "\t\tIO priority: normal\n"; + VERIFY_IS_TRUE(parser._sResult == pszExpectedResult); + + parser._sResult = ""; + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushNonVolatileMemory with no drain\n" + "\t\twrite buffer size: 12341234\n" + "\t\twrite buffer source: 'x:\\foo\\bar.dat'\n" + "\t\tperforming read test\n" + "\t\tblock size: 65536\n" + "\t\tusing random I/O (alignment: 65536)\n" + "\t\tnumber of outstanding I/O operations: 2\n" + "\t\tthread stride size: 0\n" + "\t\tIO priority: normal\n"; + VERIFY_IS_TRUE(parser._sResult == pszExpectedResult); + + parser._sResult = ""; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::Off); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::Undefined); + target.SetCacheMode(TargetCacheMode::DisableLocalCache); target.SetTemporaryFileHint(true); parser._PrintTarget(target, false, true, false); pszExpectedResult = "\tpath: ''\n" \ diff --git a/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp b/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp index 000571b..dcbdc64 100644 --- a/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp +++ b/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp @@ -155,6 +155,44 @@ namespace UnitTests " \n" " \n" " \n" + " \n" + " 10\n" + " 20\n" + " 30\n" + " 40\n" + " 50\n" + " true\n" + " true\n" + " \n" + " \n" + " testfile.dat\n" + " 100\n" + " 84\n" + " true\n" + " \n" + " \n" + " testfile1.dat\n" + " 100\n" + " 84\n" + " true\n" + " ViewOfFile" + " \n" + " \n" + " testfile2.dat\n" + " 100\n" + " 84\n" + " true\n" + " NonVolatileMemory" + " \n" + " \n" + " testfile3.dat\n" + " 100\n" + " 84\n" + " true\n" + " NonVolatileMemoryNoDrain" + " \n" + " \n" + " \n" " \n" "\n"); /* @@ -184,7 +222,7 @@ namespace UnitTests VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); vector vSpans(profile.GetTimeSpans()); - VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)2); VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)20); VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)30); @@ -208,6 +246,7 @@ namespace UnitTests VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 333); VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == true); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)3344); @@ -237,6 +276,7 @@ namespace UnitTests VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); @@ -267,7 +307,8 @@ namespace UnitTests VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableLocalCache); - VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); @@ -297,6 +338,7 @@ namespace UnitTests VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); @@ -315,6 +357,48 @@ namespace UnitTests VERIFY_IS_TRUE(t.GetUseLargePages() == false); VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintLow); VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::None); + + VERIFY_ARE_EQUAL(vSpans[1].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[1].GetWarmup(), (UINT32)20); + VERIFY_ARE_EQUAL(vSpans[1].GetCooldown(), (UINT32)30); + VERIFY_ARE_EQUAL(vSpans[1].GetRandSeed(), (UINT32)40); + VERIFY_ARE_EQUAL(vSpans[1].GetThreadCount(), (DWORD)50); + VERIFY_ARE_EQUAL(vSpans[1].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[1].GetDisableAffinity() == true); + VERIFY_IS_TRUE(vSpans[1].GetMeasureLatency() == true); + + vTargets = vSpans[1].GetTargets(); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)4); + + t = vTargets[0]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + + // verify FlushViewOfFile + t = vTargets[1]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile1.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::ViewOfFile); + + // verify RtlFlushNonVolatileMemory + t = vTargets[2]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile2.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemory); + + // verify RtlFlushNonVolatileMemoryNoDrain + t = vTargets[3]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile3.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); } void XmlProfileParserUnitTests::Test_ParseFilePrecreateFilesUseMaxSize() diff --git a/XmlProfileParser/XmlProfileParser.cpp b/XmlProfileParser/XmlProfileParser.cpp index 660693b..376e717 100644 --- a/XmlProfileParser/XmlProfileParser.cpp +++ b/XmlProfileParser/XmlProfileParser.cpp @@ -776,6 +776,16 @@ HRESULT XmlProfileParser::_ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget) } } + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "MemoryMappedIo", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetMemoryMappedIoMode(MemoryMappedIoMode::On); + } + } + if (SUCCEEDED(hr)) { bool fBool; @@ -807,6 +817,31 @@ HRESULT XmlProfileParser::_ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget) } } + if (SUCCEEDED(hr)) + { + string sFlushType; + hr = _GetString(pXmlNode, "FlushType", &sFlushType); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sFlushType == "ViewOfFile") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + } + else if (sFlushType == "NonVolatileMemory") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + } + else if (sFlushType == "NonVolatileMemoryNoDrain") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + } + else + { + hr = E_INVALIDARG; + } + } + } + if (SUCCEEDED(hr)) { hr = _ParseWriteBufferContent(pXmlNode, pTarget); diff --git a/XmlProfileParser/diskspd.xsd b/XmlProfileParser/diskspd.xsd index 46e5955..7d47c05 100644 --- a/XmlProfileParser/diskspd.xsd +++ b/XmlProfileParser/diskspd.xsd @@ -65,6 +65,20 @@ + + + + + + + + + + + + + + diff --git a/XmlResultParser/xmlresultparser.cpp b/XmlResultParser/XmlResultParser.cpp similarity index 100% rename from XmlResultParser/xmlresultparser.cpp rename to XmlResultParser/XmlResultParser.cpp diff --git a/diskspd.wprp b/diskspd.wprp new file mode 100644 index 0000000..5f01e79 --- /dev/null +++ b/diskspd.wprp @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj b/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj index d7d34df..ca221f3 100644 --- a/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj +++ b/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj @@ -85,6 +85,7 @@ true false true + MultiThreadedDebug true @@ -97,6 +98,7 @@ true false true + MultiThreadedDebug true @@ -110,6 +112,7 @@ true true true + MultiThreaded true @@ -125,6 +128,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj b/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj index 215fa6b..3b52a36 100644 --- a/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj +++ b/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj @@ -90,6 +90,7 @@ true false true + MultiThreadedDebug true @@ -103,6 +104,7 @@ true false true + MultiThreadedDebug true @@ -117,6 +119,7 @@ true true true + MultiThreaded true @@ -133,6 +136,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/Common/Common.vcxproj b/diskspd_vs/Common/Common.vcxproj index 08f6326..65fd1af 100644 --- a/diskspd_vs/Common/Common.vcxproj +++ b/diskspd_vs/Common/Common.vcxproj @@ -74,6 +74,7 @@ true false true + MultiThreadedDebug true @@ -86,6 +87,7 @@ true false true + MultiThreadedDebug true @@ -99,6 +101,7 @@ true true true + MultiThreaded true @@ -114,6 +117,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj b/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj index 4b5f761..4e47649 100644 --- a/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj +++ b/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj @@ -85,6 +85,7 @@ true false true + MultiThreadedDebug true @@ -97,6 +98,7 @@ true false true + MultiThreadedDebug true @@ -110,6 +112,7 @@ true true true + MultiThreaded true @@ -125,6 +128,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/ResultParser/ResultParser.vcxproj b/diskspd_vs/ResultParser/ResultParser.vcxproj index 3a0a10a..f5a7355 100644 --- a/diskspd_vs/ResultParser/ResultParser.vcxproj +++ b/diskspd_vs/ResultParser/ResultParser.vcxproj @@ -85,6 +85,7 @@ true false true + MultiThreadedDebug true @@ -97,6 +98,7 @@ true false true + MultiThreadedDebug true @@ -110,6 +112,7 @@ true true true + MultiThreaded true @@ -125,6 +128,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj b/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj index 155854b..02c0d61 100644 --- a/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj +++ b/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj @@ -85,6 +85,7 @@ true false true + MultiThreadedDebug true @@ -97,6 +98,7 @@ true false true + MultiThreadedDebug true @@ -110,6 +112,7 @@ true true true + MultiThreaded true @@ -125,6 +128,7 @@ true true true + MultiThreaded true diff --git a/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj b/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj index a0f4a0d..bafde77 100644 --- a/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj +++ b/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj @@ -89,6 +89,7 @@ true false true + MultiThreadedDebug Windows @@ -105,6 +106,7 @@ true false true + MultiThreadedDebug Windows @@ -122,6 +124,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true true + MultiThreaded Windows @@ -141,6 +144,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true true + MultiThreaded Windows @@ -150,10 +154,10 @@ - + - +