Skip to content

Commit 3c154ff

Browse files
authored
Pull request for 2.0.21a release (microsoft#74)
* Support for memory mapped I/O Added support for memory mapped I/O to enhance storage-related memory device development and testing. * Support for ETW events Added support for ETW events to distinguish between various phases and to trace individual I/Os. * Support for displaying system information Added support for displaying system information such as the computer name and the time the run was started. * Changed case of various files Changed the case of various files and directories to match the rest of the project. * Remove the use of runtime DLLs in Visual Studio Updated the Visual Studio projects to remove the use of runtime DLLs. * Depreciated in-branch documentation Depreciated the use of in-branch documentation in favor of https://github.com/Microsoft/diskspd/wiki/Home.
1 parent a2d7fcf commit 3c154ff

32 files changed

+1261
-58
lines changed

CmdLineParser/CmdLineParser.cpp

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
176176
printf(" -l Use large pages for IO buffers\n");
177177
printf(" -L measure latency statistics\n");
178178
printf(" -n disable default affinity (-a)\n");
179+
printf(" -N<vni> specify the flush mode for memory mapped I/O\n");
180+
printf(" v : uses the FlushViewOfFile API\n");
181+
printf(" n : uses the RtlFlushNonVolatileMemory API\n");
182+
printf(" i : uses RtlFlushNonVolatileMemory without waiting for the flush to drain\n");
183+
printf(" [default: none]\n");
179184
printf(" -o<count> number of outstanding I/O requests per target per thread\n");
180185
printf(" (1=synchronous I/O, unless more than 1 thread is specified with -F)\n");
181186
printf(" [default=2]\n");
@@ -194,14 +199,16 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
194199
printf(" manipulate a shared offset with InterlockedIncrement, which may reduce throughput,\n");
195200
printf(" but promotes a more sequential pattern.\n");
196201
printf(" (ignored if -r specified, -si conflicts with -T and -p)\n");
197-
printf(" -S[bhruw] control caching behavior [default: caching is enabled, no writethrough]\n");
202+
printf(" -S[bhmruw] control caching behavior [default: caching is enabled, no writethrough]\n");
198203
printf(" non-conflicting flags may be combined in any order; ex: -Sbw, -Suw, -Swu\n");
199204
printf(" -S equivalent to -Su\n");
200205
printf(" -Sb enable caching (default, explicitly stated)\n");
201206
printf(" -Sh equivalent -Suw\n");
207+
printf(" -Sm enable memory mapped I/O\n");
202208
printf(" -Su disable software caching, equivalent to FILE_FLAG_NO_BUFFERING\n");
203209
printf(" -Sr disable local caching, with remote sw caching enabled; only valid for remote filesystems\n");
204-
printf(" -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH\n");
210+
printf(" -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH or\n");
211+
printf(" non-temporal writes for memory mapped I/O (-Sm)\n");
205212
printf(" -t<count> number of threads per target (conflicts with -F)\n");
206213
printf(" -T<offs>[K|M|G|b] starting stride between I/O operations performed on the same target by different threads\n");
207214
printf(" [default=0] (starting offset = base file offset + (thread number * <offs>)\n");
@@ -480,6 +487,39 @@ bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan)
480487
return fOk;
481488
}
482489

490+
bool CmdLineParser::_ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode)
491+
{
492+
assert(nullptr != arg);
493+
assert(0 != *arg);
494+
495+
bool fOk = true;
496+
if (*(arg + 1) != '\0')
497+
{
498+
const char *c = arg + 1;
499+
if (_stricmp(c, "v") == 0)
500+
{
501+
*FlushMode = MemoryMappedIoFlushMode::ViewOfFile;
502+
}
503+
else if (_stricmp(c, "n") == 0)
504+
{
505+
*FlushMode = MemoryMappedIoFlushMode::NonVolatileMemory;
506+
}
507+
else if (_stricmp(c, "i") == 0)
508+
{
509+
*FlushMode = MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain;
510+
}
511+
else
512+
{
513+
fOk = false;
514+
}
515+
}
516+
else
517+
{
518+
fOk = false;
519+
}
520+
return fOk;
521+
}
522+
483523
bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch)
484524
{
485525
/* Process any command-line options */
@@ -530,6 +570,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
530570
// this allows for conflicts to be thrown for mixed -h/-S as needed.
531571
TargetCacheMode t = TargetCacheMode::Undefined;
532572
WriteThroughMode w = WriteThroughMode::Undefined;
573+
MemoryMappedIoMode m = MemoryMappedIoMode::Undefined;
574+
MemoryMappedIoFlushMode f = MemoryMappedIoFlushMode::Undefined;
533575

534576
TimeSpan timeSpan;
535577
bool bExit = false;
@@ -837,6 +879,13 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
837879
timeSpan.SetDisableAffinity(true);
838880
break;
839881

882+
case 'N':
883+
if (!_ParseFlushParameter(arg, &f))
884+
{
885+
fError = true;
886+
}
887+
break;
888+
840889
case 'o': //request count (1==synchronous)
841890
{
842891
int c = atoi(arg + 1);
@@ -989,14 +1038,27 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
9891038
break;
9901039
case 'h':
9911040
if (t == TargetCacheMode::Undefined &&
992-
w == WriteThroughMode::Undefined)
1041+
w == WriteThroughMode::Undefined &&
1042+
m == MemoryMappedIoMode::Undefined)
9931043
{
9941044
t = TargetCacheMode::DisableOSCache;
9951045
w = WriteThroughMode::On;
9961046
}
9971047
else
9981048
{
999-
fprintf(stderr, "-Sh conflicts with earlier specification of cache/writethrough\n");
1049+
fprintf(stderr, "-Sh conflicts with earlier specification of cache/writethrough/memory mapped\n");
1050+
fError = true;
1051+
}
1052+
break;
1053+
case 'm':
1054+
if (m == MemoryMappedIoMode::Undefined &&
1055+
t != TargetCacheMode::DisableOSCache)
1056+
{
1057+
m = MemoryMappedIoMode::On;
1058+
}
1059+
else
1060+
{
1061+
fprintf(stderr, "-Sm conflicts with earlier specification of memory mapped IO/unbuffered IO\n");
10001062
fError = true;
10011063
}
10021064
break;
@@ -1012,13 +1074,14 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
10121074
}
10131075
break;
10141076
case 'u':
1015-
if (t == TargetCacheMode::Undefined)
1077+
if (t == TargetCacheMode::Undefined &&
1078+
m == MemoryMappedIoMode::Undefined)
10161079
{
10171080
t = TargetCacheMode::DisableOSCache;
10181081
}
10191082
else
10201083
{
1021-
fprintf(stderr, "-Su conflicts with earlier specification of cache mode\n");
1084+
fprintf(stderr, "-Su conflicts with earlier specification of cache mode/memory mapped IO\n");
10221085
fError = true;
10231086
}
10241087
break;
@@ -1043,7 +1106,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
10431106
// bare -S, parse loop did not advance
10441107
if (!fError && idx == 1)
10451108
{
1046-
if (t == TargetCacheMode::Undefined)
1109+
if (t == TargetCacheMode::Undefined &&
1110+
m == MemoryMappedIoMode::Undefined)
10471111
{
10481112
t = TargetCacheMode::DisableOSCache;
10491113
}
@@ -1283,7 +1347,7 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
12831347
return false;
12841348
}
12851349

1286-
// apply resultant cache/writethrough modes to the targets
1350+
// apply resultant cache/writethrough/memory mapped io modes to the targets
12871351
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
12881352
{
12891353
if (t != TargetCacheMode::Undefined)
@@ -1294,6 +1358,14 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
12941358
{
12951359
i->SetWriteThroughMode(w);
12961360
}
1361+
if (m != MemoryMappedIoMode::Undefined)
1362+
{
1363+
i->SetMemoryMappedIoMode(m);
1364+
}
1365+
if (f != MemoryMappedIoFlushMode::Undefined)
1366+
{
1367+
i->SetMemoryMappedIoFlushMode(f);
1368+
}
12971369
}
12981370

12991371
// ... and apply targets to the timespan

CmdRequestCreator/CmdRequestCreator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ int __cdecl main(int argc, const char* argv[])
152152
return 1;
153153
}
154154

155+
TraceLoggingRegister(g_hEtwProvider);
156+
155157
//
156158
// call IO request generator
157159
//
@@ -179,6 +181,8 @@ int __cdecl main(int argc, const char* argv[])
179181
return 1;
180182
}
181183

184+
TraceLoggingUnregister(g_hEtwProvider);
185+
182186
if( NULL != synch.hStartEvent )
183187
{
184188
CloseHandle(synch.hStartEvent);

Common/CmdLineParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class CmdLineParser
4545
bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile);
4646

4747
bool _ParseETWParameter(const char *arg, Profile *pProfile);
48+
bool _ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode );
4849
bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan);
4950

5051
void _DisplayUsageInfo(const char *pszFilename) const;

Common/Common.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ SOFTWARE.
2929

3030
#include "Common.h"
3131

32+
TRACELOGGING_DEFINE_PROVIDER(g_hEtwProvider,
33+
"Microsoft-Windows-DiskSpd", // {CA13DB84-D0A9-5145-FCA4-468DA92FDC2D}
34+
(0xca13db84, 0xd0a9, 0x5145, 0xfc, 0xa4, 0x46, 0x8d, 0xa9, 0x2f, 0xdc, 0x2d));
35+
3236
SystemInformation g_SystemInformation;
3337

3438
UINT64 PerfTimer::GetTime()
@@ -288,6 +292,28 @@ string Target::GetXml() const
288292
break;
289293
}
290294

295+
// MemoryMappedIoMode::Off is implied default
296+
switch (_memoryMappedIoMode)
297+
{
298+
case MemoryMappedIoMode::On:
299+
sXml += "<MemoryMappedIo>true</MemoryMappedIo>\n";
300+
break;
301+
}
302+
303+
// MemoryMappedIoFlushMode::Undefined is implied default
304+
switch (_memoryMappedIoFlushMode)
305+
{
306+
case MemoryMappedIoFlushMode::ViewOfFile:
307+
sXml += "<FlushType>ViewOfFile</FlushType>\n";
308+
break;
309+
case MemoryMappedIoFlushMode::NonVolatileMemory:
310+
sXml += "<FlushType>NonVolatileMemory</FlushType>\n";
311+
break;
312+
case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain:
313+
sXml += "<FlushType>NonVolatileMemoryNoDrain</FlushType>\n";
314+
break;
315+
}
316+
291317
sXml += "<WriteBufferContent>\n";
292318
if (_fZeroWriteBuffers)
293319
{
@@ -854,6 +880,26 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
854880
}
855881
}
856882

883+
if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::On)
884+
{
885+
if (timeSpan.GetCompletionRoutines())
886+
{
887+
fprintf(stderr, "ERROR: completion routines (-x) can't be used with memory mapped IO (-Sm)\n");
888+
fOk = false;
889+
}
890+
if (target.GetCacheMode() == TargetCacheMode::DisableOSCache)
891+
{
892+
fprintf(stderr, "ERROR: unbuffered IO (-Su or -Sh) can't be used with memory mapped IO (-Sm)\n");
893+
fOk = false;
894+
}
895+
}
896+
897+
if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off &&
898+
target.GetMemoryMappedIoFlushMode() != MemoryMappedIoFlushMode::Undefined)
899+
{
900+
fprintf(stderr, "ERROR: memory mapped flush mode (-N) can only be specified with memory mapped IO (-Sm)\n");
901+
}
902+
857903
// in the cases where there is only a single configuration specified for each target (e.g., cmdline),
858904
// currently there are no validations specific to individual targets (e.g., pre-existing files)
859905
// 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)
9601006
return pBuffer;
9611007
}
9621008

1009+
bool ThreadParameters::InitializeMappedViewForTarget(Target& target, DWORD DesiredAccess)
1010+
{
1011+
bool fOk = true;
1012+
DWORD dwProtect = PAGE_READWRITE;
1013+
1014+
if (DesiredAccess == GENERIC_READ)
1015+
{
1016+
dwProtect = PAGE_READONLY;
1017+
}
1018+
1019+
HANDLE hFile = CreateFileMapping(target.GetMappedViewFileHandle(), NULL, dwProtect, 0, 0, NULL);
1020+
fOk = (hFile != NULL);
1021+
if (fOk)
1022+
{
1023+
DWORD dwDesiredAccess = FILE_MAP_WRITE;
1024+
1025+
if (DesiredAccess == GENERIC_READ)
1026+
{
1027+
dwDesiredAccess = FILE_MAP_READ;
1028+
}
1029+
1030+
BYTE *mapView = (BYTE*) MapViewOfFile(hFile, dwDesiredAccess, 0, 0, 0);
1031+
fOk = (mapView != NULL);
1032+
if (fOk)
1033+
{
1034+
target.SetMappedView(mapView);
1035+
}
1036+
else
1037+
{
1038+
fprintf(stderr, "FATAL ERROR: Could not map view for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError());
1039+
}
1040+
}
1041+
else
1042+
{
1043+
fprintf(stderr, "FATAL ERROR: Could not create a file mapping for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError());
1044+
}
1045+
return fOk;
1046+
}
1047+
9631048
DWORD ThreadParameters::GetTotalRequestCount() const
9641049
{
9651050
DWORD cRequests = 0;
@@ -977,3 +1062,47 @@ DWORD ThreadParameters::GetTotalRequestCount() const
9771062

9781063
return cRequests;
9791064
}
1065+
1066+
void EtwResultParser::ParseResults(vector<Results> vResults)
1067+
{
1068+
if (TraceLoggingProviderEnabled(g_hEtwProvider,
1069+
TRACE_LEVEL_NONE,
1070+
DISKSPD_TRACE_INFO))
1071+
{
1072+
for (size_t ullResults = 0; ullResults < vResults.size(); ullResults++)
1073+
{
1074+
const Results& results = vResults[ullResults];
1075+
for (size_t ullThread = 0; ullThread < results.vThreadResults.size(); ullThread++)
1076+
{
1077+
const ThreadResults& threadResults = results.vThreadResults[ullThread];
1078+
for (const auto& targetResults : threadResults.vTargetResults)
1079+
{
1080+
if (targetResults.ullReadIOCount)
1081+
{
1082+
_WriteResults(IOOperation::ReadIO, targetResults, ullThread);
1083+
}
1084+
if (targetResults.ullWriteIOCount)
1085+
{
1086+
_WriteResults(IOOperation::WriteIO, targetResults, ullThread);
1087+
}
1088+
}
1089+
}
1090+
}
1091+
}
1092+
}
1093+
1094+
void EtwResultParser::_WriteResults(IOOperation type, const TargetResults& targetResults, size_t ullThread)
1095+
{
1096+
UINT64 ullIOCount = (type == IOOperation::ReadIO) ? targetResults.ullReadIOCount : targetResults.ullWriteIOCount;
1097+
UINT64 ullBytesCount = (type == IOOperation::ReadIO) ? targetResults.ullReadBytesCount : targetResults.ullWriteBytesCount;
1098+
1099+
TraceLoggingWrite(g_hEtwProvider,
1100+
"Statistics",
1101+
TraceLoggingLevel((TRACE_LEVEL_NONE)),
1102+
TraceLoggingString((type == IOOperation::ReadIO) ? "Read" : "Write", "IO Type"),
1103+
TraceLoggingUInt64(ullThread, "Thread"),
1104+
TraceLoggingUInt64(ullBytesCount, "Bytes"),
1105+
TraceLoggingUInt64(ullIOCount, "IO Count"),
1106+
TraceLoggingString(targetResults.sPath.c_str(), "Path"),
1107+
TraceLoggingUInt64(targetResults.ullFileSize, "File Size"));
1108+
}

0 commit comments

Comments
 (0)