DISKSPD 2.2 (#209)
* add sorted data to Historgram (#197) Co-authored-by: Feng Li <fengli@microsoft.com> * multiple updates from msft internal 2.1.2 prerelease flush stdout to force XML/text results through prior to process exit fix issues identified by vs2019 build loop - 64->32 downcast, minor printf issues, _snprintf -> _snprintf_s timestamp prefixes for all verbose output dump specific time intervals for warmup/measured/cooldown to validate v. expected @ actual time of use/measurement only emit warmup/cooldown verbose output notes if there is nonzero warmup/cooldown specified in the profile minor cleanup of load thread verbose output so that everything has a consistent thread N: prefix histogram processing speedups, about 60% for XML (all percentiles) implicitly seal/sort histogram on first read operation, reset on subsequent inserts; save repeated re-sorting save histogram percentile iterator so that asecending percentile queries do not restart from lowest sample min/max in terms of begin/rbegin iterator show latency histogram bucket counts in XML results; potential work to moderate histogram size unit test coverage * DISKSPD 2.2 --------- Co-authored-by: FengLiMS <128095530+FengLiMS@users.noreply.github.com> Co-authored-by: Feng Li <fengli@microsoft.com> Co-authored-by: Dan Lovinger <danlo@ntdev.microsoft.com>
This commit is contained in:
Родитель
206bae568c
Коммит
2ac91a462b
|
@ -161,30 +161,36 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
|
|||
" #<physical drive number>\n"
|
||||
" <drive_letter>:\n"
|
||||
"\n"
|
||||
"Sizes, offsets and lengths are specified as integer bytes, or with an\n"
|
||||
"optional suffix of KMGT (KiB/MiB/GiB/TiB) or b (for blocks, see -b).\n"
|
||||
"Examples: 4k = 4096\n"
|
||||
" with -b4k, 8b = 32768 (8 * 4KiB)\n"
|
||||
"\n"
|
||||
"Available options:\n"
|
||||
" -? display usage information\n"
|
||||
" -ag group affinity - affinitize threads round-robin to cores in Processor Groups 0 - n.\n"
|
||||
" Group 0 is filled before Group 1, and so forth.\n"
|
||||
" -:<flags> experimental behaviors, as a bitmask of flags. current:\n"
|
||||
" 1 - allow throughput rate limit sleeps >1ms if indicated by rate\n"
|
||||
" -ag group affinity - threads assigned round-robin to CPUs by processor groups, 0 - n.\n"
|
||||
" Groups are filled from lowest to highest processor before moving to the next.\n"
|
||||
" [default; use -n to disable default affinity]\n"
|
||||
" -ag#,#[,#,...]> advanced CPU affinity - affinitize threads round-robin to the CPUs provided. The g# notation\n"
|
||||
" specifies Processor Groups for the following CPU core #s. Multiple Processor Groups\n"
|
||||
" may be specified, and groups/cores may be repeated. If no group is specified, 0 is assumed.\n"
|
||||
" Additional groups/processors may be added, comma separated, or on separate parameters.\n"
|
||||
" -a[g#,]#[,#,...]> advanced CPU affinity - threads assigned round-robin to the CPUs stated, in order of\n"
|
||||
" specification; g# is the processor group for the following CPUs. If no group is\n"
|
||||
" stated, 0 is default. Additional groups/processors can be added, comma separated,\n"
|
||||
" on the same or separate -a parameters.\n"
|
||||
" Examples: -a0,1,2 and -ag0,0,1,2 are equivalent.\n"
|
||||
" -ag0,0,1,2,g1,0,1,2 specifies the first three cores in groups 0 and 1.\n"
|
||||
" -ag0,0,1,2 -ag1,0,1,2 is equivalent.\n"
|
||||
" -b<size>[KMGT] block size in bytes or KiB/MiB/GiB/TiB [default=64K]\n"
|
||||
" -B<offs>[KMGTb] base target offset in bytes or KiB/MiB/GiB/TiB/blocks [default=0]\n"
|
||||
" (offset from the beginning of the file)\n"
|
||||
" -c<size>[KMGTb] create files of the given size.\n"
|
||||
" Size can be stated in bytes or KiB/MiB/GiB/TiB/blocks\n"
|
||||
" -ag0,0,1,2,g1,0,1,2 specifies the first three CPUs in groups 0 and 1.\n"
|
||||
" -ag0,0,1,2,g1,0,1,2 and -ag0,0,1,2 -ag1,0,1,2 are equivalent.\n"
|
||||
" -b<size> IO size, defines the block \'b\' for sizes stated in units of blocks [default=64K]\n"
|
||||
" -B<base>[:length] bounds; specify range of target to issue IO to - base offset and length\n"
|
||||
" (default: IO is issued across the entire target)\n"
|
||||
" -c<size> create file targets of the given size. Conflicts with non-file target specifications.\n"
|
||||
" -C<seconds> cool down time - duration of the test after measurements finished [default=0s].\n"
|
||||
" -D<milliseconds> Capture IOPs statistics in intervals of <milliseconds>; these are per-thread\n"
|
||||
" per-target: text output provides IOPs standard deviation, XML provides the full\n"
|
||||
" IOPs time series in addition. [default=1000, 1 second].\n"
|
||||
" -d<seconds> duration (in seconds) to run test [default=10s]\n"
|
||||
" -f<size>[KMGTb] target size - use only the first <size> bytes or KiB/MiB/GiB/TiB/blocks of the file/disk/partition,\n"
|
||||
" for example to test only the first sectors of a disk\n"
|
||||
" -f<size> maximum target offset to issue IO to (non-inclusive); -Bbase -f(base+length) is the same\n"
|
||||
" as -Bbase:length. For example, to test only the first sectors of a disk.\n"
|
||||
" -f<rst> open file with one or more additional access hints\n"
|
||||
" r : the FILE_FLAG_RANDOM_ACCESS hint\n"
|
||||
" s : the FILE_FLAG_SEQUENTIAL_SCAN hint\n"
|
||||
|
@ -216,7 +222,7 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
|
|||
" (ignored if -r is specified, makes sense only with -o2 or greater)\n"
|
||||
" -P<count> enable printing a progress dot after each <count> [default=65536]\n"
|
||||
" completed I/O operations, counted separately by each thread \n"
|
||||
" -r[align[KMGTb]] random I/O aligned to <align> in bytes/KiB/MiB/GiB/TiB/blocks (overrides -s)\n"
|
||||
" -r[align] random I/O aligned to [align] byte offsets within the target range (overrides -s)\n"
|
||||
" [default alignment=block size (-b)]\n"
|
||||
" -rd<dist>[params] specify an non-uniform distribution for random IO in the target\n"
|
||||
" [default uniformly random]\n"
|
||||
|
@ -234,22 +240,21 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
|
|||
" next 10GiB, 5%% IO in the next 20GiB and the remaining 5%% of IO in the remaining\n"
|
||||
" capacity of the target. If the target is only 20G, the distribution truncates at\n"
|
||||
" 90/10G:0:10G and all IO is directed to the first 10G (equivalent to -f10G).\n"
|
||||
" -rs<percentage> percentage of requests which should be issued randomly. When used, -r may be used to\n"
|
||||
" specify IO alignment (applies to both the random and sequential portions of the load).\n"
|
||||
" Sequential IO runs will be homogeneous if a mixed ratio is specified (-w), and run\n"
|
||||
" lengths will follow a geometric distribution based on the percentage split.\n"
|
||||
" -rs<percentage> percentage of requests which should be issued randomly; -r is used to specify IO alignment.\n"
|
||||
" Sequential IO runs are homogeneous when a mixed r/w ratio is specified (-w) and their lengths\n"
|
||||
" follow a geometric distribution based on the percentage (chance of next IO being sequential).\n"
|
||||
" -R[p]<text|xml> output format. With the p prefix, the input profile (command line or XML) is validated and\n"
|
||||
" re-output in the specified format without running load, useful for checking or building\n"
|
||||
" complex profiles.\n"
|
||||
" [default: text]\n"
|
||||
" -s[i][align[KMGTb]] stride size of <align> in bytes/KiB/MiB/GiB/TiB/blocks, alignment/offset between operations\n"
|
||||
" -s[i][align] stride size of [align] bytes, alignment & offset between operations\n"
|
||||
" [default=non-interlocked, default alignment=block size (-b)]\n"
|
||||
" By default threads track independent sequential IO offsets starting at offset 0 of the target.\n"
|
||||
" By default threads track independent sequential IO offsets starting at base offset of the target.\n"
|
||||
" With multiple threads this results in threads overlapping their IOs - see -T to divide\n"
|
||||
" them into multiple separate sequential streams on the target.\n"
|
||||
" With the optional i qualifier (-si) threads interlock on a shared sequential offset.\n"
|
||||
" Interlocked operations may introduce overhead but make it possible to issue a single\n"
|
||||
" sequential stream to a target which responds faster than a one thread can drive.\n"
|
||||
" sequential stream to a target which responds faster than one thread can drive.\n"
|
||||
" (ignored if -r specified, -si conflicts with -p, -rs and -T)\n"
|
||||
" -S[bhmruw] control caching behavior [default: caching is enabled, no writethrough]\n"
|
||||
" non-conflicting flags may be combined in any order; ex: -Sbw, -Suw, -Swu\n"
|
||||
|
@ -262,20 +267,21 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
|
|||
" -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH or\n"
|
||||
" non-temporal writes for memory mapped I/O (-Sm)\n"
|
||||
" -t<count> number of threads per target (conflicts with -F)\n"
|
||||
" -T<offs>[KMGTb] starting stride between I/O operations performed on the same target by different threads\n"
|
||||
" [default=0] (starting offset = base file offset + (thread number * <offs>)\n"
|
||||
" only applies with #threads > 1\n"
|
||||
" -v verbose mode\n"
|
||||
" -T<offs> starting separation between I/O operations performed on the same target by different threads\n"
|
||||
" [default=0] (starting offset = base target offset + (thread number * <offs>)\n"
|
||||
" only applies to -s sequential IO with #threads > 1, conflicts with -r and -si\n"
|
||||
" -v[s] verbose mode - with s, only provide additional summary statistics\n"
|
||||
" -w<percentage> percentage of write requests (-w and -w0 are equivalent and result in a read-only workload).\n"
|
||||
" absence of this switch indicates 100%% reads\n"
|
||||
" IMPORTANT: a write test will destroy existing data without a warning\n"
|
||||
" -W<seconds> warm up time - duration of the test before measurements start [default=5s]\n"
|
||||
" -x use completion routines instead of I/O Completion Ports\n"
|
||||
" -X<filepath> use an XML file to configure the workload. Combine with -R, -v and -z to override profile defaults.\n"
|
||||
" -X<filepath> use an XML file to configure the workload. Profile defaults for -W/d/C (durations) and -R/v/z\n"
|
||||
" (output format, verbosity and random seed) may be overriden by direct specification.\n"
|
||||
" Targets can be defined in XML profiles as template paths of the form *<integer> (*1, *2, ...).\n"
|
||||
" When run, specify the paths to substitute for the template paths in order on the command line.\n"
|
||||
" The first specified target is *1, second is *2, and so on.\n"
|
||||
" Example: diskspd -Xprof.xml first.bin second.bin (prof.xml using *1 and *2)\n"
|
||||
" Example: diskspd -d60 -Xprof.xml first.bin second.bin (prof.xml using *1 and *2, 60s run)\n"
|
||||
" -z[seed] set random seed [with no -z, seed=0; with plain -z, seed is based on system run time]\n"
|
||||
"\n"
|
||||
"Write buffers:\n"
|
||||
|
@ -283,10 +289,10 @@ void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const
|
|||
" -Zr per IO random buffers used for write tests - this incurrs additional run-time\n"
|
||||
" overhead to create random content and shouln't be compared to results run\n"
|
||||
" without -Zr\n"
|
||||
" -Z<size>[KMGb] use a <size> buffer filled with random data as a source for write operations.\n"
|
||||
" -Z<size>[KMGb],<file> use a <size> buffer filled with data from <file> as a source for write operations.\n"
|
||||
" -Z<size> use a <size> buffer filled with random data as a source for write operations.\n"
|
||||
" -Z<size>,<file> use a <size> buffer filled with data from <file> as a source for write operations.\n"
|
||||
"\n"
|
||||
" By default, the write buffers are filled with a repeating pattern (0, 1, 2, ..., 255, 0, 1, ...)\n"
|
||||
" By default, write source buffers are filled with a repeating pattern (0, 1, 2, ..., 255, 0, 1, ...)\n"
|
||||
"\n"
|
||||
"Synchronization:\n"
|
||||
" -ys<eventname> signals event <eventname> before starting the actual run (no warmup)\n"
|
||||
|
@ -475,12 +481,12 @@ bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan)
|
|||
{
|
||||
fOk = false;
|
||||
}
|
||||
// have a parsed core number
|
||||
// have a parsed CPU number
|
||||
else
|
||||
{
|
||||
if (nNum > MAXBYTE)
|
||||
{
|
||||
fprintf(stderr, "ERROR: core %u is out of range\n", nNum);
|
||||
fprintf(stderr, "ERROR: CPU %u is out of range\n", nNum);
|
||||
fOk = false;
|
||||
}
|
||||
else
|
||||
|
@ -514,7 +520,7 @@ bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan)
|
|||
|
||||
if (fOk && nNum > MAXBYTE)
|
||||
{
|
||||
fprintf(stderr, "ERROR: core %u is out of range\n", nNum);
|
||||
fprintf(stderr, "ERROR: CPU %u is out of range\n", nNum);
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
|
@ -537,7 +543,7 @@ bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan)
|
|||
|
||||
if (fOk)
|
||||
{
|
||||
// fprintf(stderr, "FINAL parsed group %d core %d\n", nGroup, nNum);
|
||||
// fprintf(stderr, "FINAL parsed group %d CPU %d\n", nGroup, nNum);
|
||||
pTimeSpan->AddAffinityAssignment((WORD)nGroup, (BYTE)nNum);
|
||||
}
|
||||
|
||||
|
@ -732,15 +738,18 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
ParseState isXMLResultFormat = ParseState::Unknown;
|
||||
ParseState isProfileOnly = ParseState::Unknown;
|
||||
ParseState isVerbose = ParseState::Unknown;
|
||||
ParseState isVerboseStats = ParseState::Unknown;
|
||||
ParseState isRandomSeed = ParseState::Unknown;
|
||||
ParseState isWarmupTime = ParseState::Unknown;
|
||||
ParseState isDurationTime = ParseState::Unknown;
|
||||
ParseState isCooldownTime = ParseState::Unknown;
|
||||
ParseState isExperimentFlags = ParseState::Unknown;
|
||||
|
||||
ULONG randomSeedValue = 0;
|
||||
ULONG warmupTime = 0;
|
||||
ULONG durationTime = 0;
|
||||
ULONG cooldownTime = 0;
|
||||
ULONG experimentFlags = 0;
|
||||
const char *xmlProfile = nullptr;
|
||||
|
||||
//
|
||||
|
@ -780,6 +789,13 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
switch(args[i][1])
|
||||
{
|
||||
|
||||
|
||||
case ':':
|
||||
// Experiment flags
|
||||
experimentFlags = atoi(arg);
|
||||
isExperimentFlags = ParseState::True;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
|
||||
// Block size does not compose with XML profile spec
|
||||
|
@ -793,9 +809,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
UINT64 ullBlockSize;
|
||||
if (_GetSizeInBytes(arg, ullBlockSize, nullptr) && ullBlockSize < MAXUINT32)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetBlockSizeInBytes((DWORD)ullBlockSize);
|
||||
i.SetBlockSizeInBytes((DWORD)ullBlockSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -896,7 +912,19 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
|
||||
case 'v':
|
||||
|
||||
if (*arg == '\0')
|
||||
{
|
||||
isVerbose = ParseState::True;
|
||||
}
|
||||
else if (*arg == 's' && *(arg+1) == '\0') // -vs
|
||||
{
|
||||
isVerboseStats = ParseState::True;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid verbose mode (-v): '%s'\n", arg);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
|
@ -984,6 +1012,16 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
pProfile->SetVerbose(true);
|
||||
}
|
||||
|
||||
if (isVerboseStats == ParseState::True)
|
||||
{
|
||||
pProfile->SetVerboseStats(true);
|
||||
}
|
||||
|
||||
if (isExperimentFlags == ParseState::True)
|
||||
{
|
||||
g_ExperimentFlags = experimentFlags;
|
||||
}
|
||||
|
||||
//
|
||||
// Apply timespan common composable parameters
|
||||
//
|
||||
|
@ -1025,6 +1063,10 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
MemoryMappedIoMode m = MemoryMappedIoMode::Undefined;
|
||||
MemoryMappedIoFlushMode f = MemoryMappedIoFlushMode::Undefined;
|
||||
|
||||
// seen base/max target offset specification yet?
|
||||
ParseState isMaxTargetOffset = ParseState::Unknown;
|
||||
ParseState isBaseTargetOffset = ParseState::Unknown;
|
||||
|
||||
bool bExit = false;
|
||||
while (nParamCnt)
|
||||
{
|
||||
|
@ -1047,6 +1089,10 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
_DisplayUsageInfo(argv[0]);
|
||||
exit(0);
|
||||
|
||||
case ':': // experiment flags
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'a': // affinity
|
||||
//-a1,2,3,4 (assign threads to cpus 1,2,3,4 (round robin))
|
||||
if (!_ParseAffinity(arg, &timeSpan))
|
||||
|
@ -1056,24 +1102,75 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
break;
|
||||
|
||||
case 'b': //block size
|
||||
// nop - block size has been taken care of before the loop
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'B': //base file offset (offset from the beginning of the file)
|
||||
case 'B': //base target offset (offset from 0) and optional length
|
||||
if (*(arg + 1) != '\0')
|
||||
{
|
||||
UINT64 cb;
|
||||
if (_GetSizeInBytes(arg + 1, cb, nullptr))
|
||||
UINT64 base;
|
||||
UINT64 len;
|
||||
const char *rest;
|
||||
|
||||
if (isBaseTargetOffset == ParseState::True)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
{
|
||||
i->SetBaseFileOffsetInBytes(cb);
|
||||
fprintf(stderr, "ERROR: base target offset (-Bbase[:length]) can only be specified once\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_GetSizeInBytes(arg + 1, base, &rest))
|
||||
{
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i.SetBaseFileOffsetInBytes(base);
|
||||
}
|
||||
|
||||
isBaseTargetOffset = ParseState::True;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid base file offset passed to -B\n");
|
||||
fprintf(stderr, "ERROR: invalid base target offset passed to -B\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rest && *rest != '\0')
|
||||
{
|
||||
if (*rest != ':')
|
||||
{
|
||||
fprintf(stderr, "ERROR: unexpected characters after -Bbase; use \':\' to separate -Bbase:length\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*(++rest) == '\0')
|
||||
{
|
||||
fprintf(stderr, "ERROR: -Bbase:length - no length provided\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isMaxTargetOffset == ParseState::True)
|
||||
{
|
||||
fprintf(stderr, "ERROR: maximum target offset (-Bbase:length or -fsize) can only be specified once\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_GetSizeInBytes(rest, len, nullptr) || base + len < base)
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid target length passed to -B\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i.SetMaxFileSize(base + len);
|
||||
}
|
||||
|
||||
isMaxTargetOffset = ParseState::True;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1088,15 +1185,15 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
UINT64 cb;
|
||||
if (_GetSizeInBytes(arg + 1, cb, nullptr))
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetFileSize(cb);
|
||||
i->SetCreateFile(true);
|
||||
i.SetFileSize(cb);
|
||||
i.SetCreateFile(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid file size passed to -c\n");
|
||||
fprintf(stderr, "ERROR: invalid target size passed to -c\n");
|
||||
fError = true;
|
||||
}
|
||||
}
|
||||
|
@ -1106,10 +1203,12 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
break;
|
||||
|
||||
case 'C': //cool down time - pass 1 composable
|
||||
case 'C': //cool down time
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'd': //duration - pass 1 composable
|
||||
case 'd': //duration
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'D': //standard deviation
|
||||
|
@ -1132,30 +1231,40 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
break;
|
||||
|
||||
case 'f':
|
||||
if (isdigit(*(arg + 1)))
|
||||
{
|
||||
UINT64 cb;
|
||||
if (_GetSizeInBytes(arg + 1, cb, nullptr))
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
{
|
||||
i->SetMaxFileSize(cb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid max file size passed to -f\n");
|
||||
fError = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ('\0' == *(arg + 1))
|
||||
{
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
// max target offset form?
|
||||
if (isdigit(*(arg + 1)))
|
||||
{
|
||||
UINT64 cb;
|
||||
|
||||
if (isMaxTargetOffset == ParseState::True)
|
||||
{
|
||||
fprintf(stderr, "ERROR: maximum target offset (-Bbase:length or -fsize) can only be specified once\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_GetSizeInBytes(arg + 1, cb, nullptr))
|
||||
{
|
||||
fprintf(stderr, "ERROR: invalid max target size passed to -f\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i.SetMaxFileSize(cb);
|
||||
}
|
||||
|
||||
isMaxTargetOffset = ParseState::True;
|
||||
break;
|
||||
}
|
||||
|
||||
// while -frs (or -fsr) are generally conflicting intentions as far as
|
||||
// the OS is concerned, do not enforce
|
||||
while (*(++arg) != '\0')
|
||||
|
@ -1163,21 +1272,21 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
switch (*arg)
|
||||
{
|
||||
case 'r':
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetRandomAccessHint(true);
|
||||
i.SetRandomAccessHint(true);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetSequentialScanHint(true);
|
||||
i.SetSequentialScanHint(true);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetTemporaryFileHint(true);
|
||||
i.SetTemporaryFileHint(true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1185,8 +1294,6 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F': //total number of threads
|
||||
|
@ -1222,15 +1329,15 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
int c = atoi(arg + 1);
|
||||
if (c > 0)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
if (isBpms)
|
||||
{
|
||||
i->SetThroughput(c);
|
||||
i.SetThroughput(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
i->SetThroughputIOPS(c);
|
||||
i.SetThroughputIOPS(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1261,10 +1368,10 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
int c = atoi(arg + 1);
|
||||
if (c > 0)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetBurstSize(c);
|
||||
i->SetUseBurstSize(true);
|
||||
i.SetBurstSize(c);
|
||||
i.SetUseBurstSize(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1279,10 +1386,10 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
int c = atoi(arg + 1);
|
||||
if (c > 0)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetThinkTime(c);
|
||||
i->SetEnableThinkTime(true);
|
||||
i.SetThinkTime(c);
|
||||
i.SetEnableThinkTime(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1298,9 +1405,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
if (x > 0 && x < 4)
|
||||
{
|
||||
PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal };
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetIOPriorityHint(hint[x - 1]);
|
||||
i.SetIOPriorityHint(hint[x - 1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1311,9 +1418,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
break;
|
||||
|
||||
case 'l': //large pages
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetUseLargePages(true);
|
||||
i.SetUseLargePages(true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1337,9 +1444,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
int c = atoi(arg + 1);
|
||||
if (c > 0)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetRequestCount(c);
|
||||
i.SetRequestCount(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1365,9 +1472,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
|
||||
case 'p': //start async IO operations with the same offset
|
||||
//makes sense only for -o2 and greater
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetUseParallelAsyncIO(true);
|
||||
i.SetUseParallelAsyncIO(true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1406,12 +1513,12 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
if (!fError)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
// if random ratio is unset and actual alignment is already specified,
|
||||
// -s was used: don't allow this for clarity of intent
|
||||
if (!i->GetRandomRatio() &&
|
||||
i->GetBlockAlignmentInBytes(true))
|
||||
if (!i.GetRandomRatio() &&
|
||||
i.GetBlockAlignmentInBytes(true))
|
||||
{
|
||||
fprintf(stderr, "ERROR: use -r to specify IO alignment when using mixed random/sequential IO (-rs)\n");
|
||||
fError = true;
|
||||
|
@ -1419,8 +1526,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
// if random ratio was already set to something other than 100% (-r)
|
||||
// then -rs was specified multiple times: catch and block this
|
||||
if (i->GetRandomRatio() &&
|
||||
i->GetRandomRatio() != 100)
|
||||
if (i.GetRandomRatio() &&
|
||||
i.GetRandomRatio() != 100)
|
||||
{
|
||||
fprintf(stderr, "ERROR: mixed random/sequential IO (-rs) specified multiple times\n");
|
||||
fError = true;
|
||||
|
@ -1432,7 +1539,7 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
// Saying -rs0 (sequential) would create an ambiguity between that and -r[nnn]. Rather
|
||||
// than bend the intepretation of -r[nnn] for the special case of -rs0 we will error
|
||||
// it out in the bounds check above.
|
||||
i->SetRandomRatio(c);
|
||||
i.SetRandomRatio(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1463,38 +1570,39 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
if (!fError)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
// Do not override -rs specification
|
||||
if (!i->GetRandomRatio())
|
||||
if (!i.GetRandomRatio())
|
||||
{
|
||||
i->SetRandomRatio(100);
|
||||
i.SetRandomRatio(100);
|
||||
}
|
||||
// Multiple -rNN?
|
||||
// Note that -rs100 -r[NN] will pass since -rs does not set alignment.
|
||||
// We are only validating a single -rNN specification.
|
||||
else if (i->GetRandomRatio() == 100 &&
|
||||
i->GetBlockAlignmentInBytes(true))
|
||||
else if (i.GetRandomRatio() == 100 &&
|
||||
i.GetBlockAlignmentInBytes(true))
|
||||
{
|
||||
fprintf(stderr, "ERROR: random IO (-r) specified multiple times\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
// -s already set the alignment?
|
||||
if (i->GetBlockAlignmentInBytes(true))
|
||||
if (i.GetBlockAlignmentInBytes(true))
|
||||
{
|
||||
fprintf(stderr, "ERROR: sequential IO (-s) conflicts with random IO (-r/-rs)\n");
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
i->SetBlockAlignmentInBytes(cb);
|
||||
i.SetBlockAlignmentInBytes(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'R': // output profile/results format engine - handled in pass 1
|
||||
case 'R': // output profile/results format engine
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 's': //stride size
|
||||
|
@ -1507,20 +1615,20 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
// ISSUE-REVIEW: this does nothing if -r is specified
|
||||
// ISSUE-REVIEW: this does nothing if -p is specified
|
||||
// ISSUE-REVIEW: this does nothing if we are single-threaded
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetUseInterlockedSequential(true);
|
||||
i.SetUseInterlockedSequential(true);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
// conflict -s with -rs/-s
|
||||
if (i->GetRandomRatio())
|
||||
if (i.GetRandomRatio())
|
||||
{
|
||||
if (i->GetRandomRatio() == 100) {
|
||||
if (i.GetRandomRatio() == 100) {
|
||||
fprintf(stderr, "ERROR: sequential IO (-s) conflicts with random IO (-r/-rs)\n");
|
||||
}
|
||||
else
|
||||
|
@ -1532,7 +1640,7 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
|
||||
// conflict with multiple -s
|
||||
if (i->GetBlockAlignmentInBytes(true))
|
||||
if (i.GetBlockAlignmentInBytes(true))
|
||||
{
|
||||
fprintf(stderr, "ERROR: sequential IO (-s) specified multiple times\n");
|
||||
fError = true;
|
||||
|
@ -1547,9 +1655,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
// The counter-case of -r0 is invalid and checked for.
|
||||
if (_GetSizeInBytes(arg + idx, cb, nullptr))
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetBlockAlignmentInBytes(cb);
|
||||
i.SetBlockAlignmentInBytes(cb);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1562,9 +1670,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
{
|
||||
// explicitly pass through the block size so that we can detect
|
||||
// -rs/-s intent conflicts when attempting to set -rs
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetBlockAlignmentInBytes(i->GetBlockSizeInBytes());
|
||||
i.SetBlockAlignmentInBytes(i.GetBlockSizeInBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1680,9 +1788,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
int c = atoi(arg + 1);
|
||||
if (c > 0)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetThreadsPerFile(c);
|
||||
i.SetThreadsPerFile(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1697,9 +1805,9 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
UINT64 cb;
|
||||
if (_GetSizeInBytes(arg + 1, cb, nullptr) && (cb > 0))
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetThreadStrideInBytes(cb);
|
||||
i.SetThreadStrideInBytes(cb);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1710,7 +1818,8 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
break;
|
||||
|
||||
case 'v': //verbose mode - handled in pass 1
|
||||
case 'v': //verbose mode
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'w': //write test [default=read]
|
||||
|
@ -1733,15 +1842,16 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
if (!fError)
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetWriteRatio(c);
|
||||
i.SetWriteRatio(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'W': //warm up time - pass 1 composable
|
||||
case 'W': //warm up time
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'x': //completion routines
|
||||
|
@ -1811,15 +1921,16 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
fError = true;
|
||||
}
|
||||
|
||||
case 'z': //random seed - pass 1 composable
|
||||
case 'z': //random seed
|
||||
// handled during composable parameter evaluation
|
||||
break;
|
||||
|
||||
case 'Z': //zero write buffers
|
||||
if (*(arg + 1) == '\0')
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetZeroWriteBuffers(true);
|
||||
i.SetZeroWriteBuffers(true);
|
||||
}
|
||||
}
|
||||
else if (*(arg + 1) == 'r' && *(arg + 2) == '\0')
|
||||
|
@ -1832,10 +1943,10 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
string sPath;
|
||||
if (_GetRandomDataWriteBufferData(string(arg + 1), cb, sPath) && (cb > 0))
|
||||
{
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
i->SetRandomDataWriteBufferSize(cb);
|
||||
i->SetRandomDataWriteBufferSourcePath(sPath);
|
||||
i.SetRandomDataWriteBufferSize(cb);
|
||||
i.SetRandomDataWriteBufferSourcePath(sPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1878,30 +1989,30 @@ bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[
|
|||
}
|
||||
|
||||
// apply resultant cache/writethrough/memory mapped io modes to the targets
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
if (t != TargetCacheMode::Undefined)
|
||||
{
|
||||
i->SetCacheMode(t);
|
||||
i.SetCacheMode(t);
|
||||
}
|
||||
if (w != WriteThroughMode::Undefined)
|
||||
{
|
||||
i->SetWriteThroughMode(w);
|
||||
i.SetWriteThroughMode(w);
|
||||
}
|
||||
if (m != MemoryMappedIoMode::Undefined)
|
||||
{
|
||||
i->SetMemoryMappedIoMode(m);
|
||||
i.SetMemoryMappedIoMode(m);
|
||||
}
|
||||
if (f != MemoryMappedIoFlushMode::Undefined)
|
||||
{
|
||||
i->SetMemoryMappedIoFlushMode(f);
|
||||
i.SetMemoryMappedIoFlushMode(f);
|
||||
}
|
||||
}
|
||||
|
||||
// ... and apply targets to the timespan
|
||||
for (auto i = vTargets.begin(); i != vTargets.end(); i++)
|
||||
for (auto &i : vTargets)
|
||||
{
|
||||
timeSpan.AddTarget(*i);
|
||||
timeSpan.AddTarget(i);
|
||||
}
|
||||
pProfile->AddTimeSpan(timeSpan);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
DISKSPD.XSD HTML "..\\XmlProfileParser\\diskspd.xsd"
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ TRACELOGGING_DEFINE_PROVIDER(g_hEtwProvider,
|
|||
(0xca13db84, 0xd0a9, 0x5145, 0xfc, 0xa4, 0x46, 0x8d, 0xa9, 0x2f, 0xdc, 0x2d));
|
||||
|
||||
SystemInformation g_SystemInformation;
|
||||
ULONG g_ExperimentFlags;
|
||||
|
||||
UINT64 PerfTimer::GetTime()
|
||||
{
|
||||
|
@ -672,6 +673,13 @@ string Profile::GetXml(UINT32 indent) const
|
|||
sprintf_s(buffer, _countof(buffer), "<Progress>%u</Progress>\n", _dwProgress);
|
||||
AddXml(sXml, buffer);
|
||||
|
||||
if (g_ExperimentFlags)
|
||||
{
|
||||
// only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified
|
||||
sprintf_s(buffer, _countof(buffer), "<ExperimentFlags>%u</ExperimentFlags>\n", g_ExperimentFlags);
|
||||
AddXml(sXml, buffer);
|
||||
}
|
||||
|
||||
if (_resultsFormat == ResultsFormat::Text)
|
||||
{
|
||||
AddXml(sXml, "<ResultFormat>text</ResultFormat>\n");
|
||||
|
@ -686,6 +694,12 @@ string Profile::GetXml(UINT32 indent) const
|
|||
}
|
||||
|
||||
AddXml(sXml, _fVerbose ? "<Verbose>true</Verbose>\n" : "<Verbose>false</Verbose>\n");
|
||||
if (_fVerboseStats)
|
||||
{
|
||||
// only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified
|
||||
AddXml(sXml, "<VerboseStats>true</VerboseStats>\n");
|
||||
}
|
||||
|
||||
if (_precreateFiles == PrecreateFiles::UseMaxSize)
|
||||
{
|
||||
AddXml(sXml, "<PrecreateFiles>UseMaxSize</PrecreateFiles>\n");
|
||||
|
@ -763,7 +777,7 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
|
|||
}
|
||||
if (fOk && !pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup].IsProcessorValid(Affinity.bProc))
|
||||
{
|
||||
fprintf(stderr, "ERROR: affinity assignment to group %u core %u not possible; group only has %u cores\n",
|
||||
fprintf(stderr, "ERROR: affinity assignment to group %u cpu %u not possible; group has a max of %u cpus\n",
|
||||
Affinity.wGroup,
|
||||
Affinity.bProc,
|
||||
pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup]._maximumProcessorCount);
|
||||
|
@ -773,22 +787,27 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
|
|||
|
||||
if (fOk && !pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup].IsProcessorActive(Affinity.bProc))
|
||||
{
|
||||
fprintf(stderr, "ERROR: affinity assignment to group %u core %u not possible; core is not active (current mask 0x%Ix)\n",
|
||||
fprintf(stderr, "ERROR: affinity assignment to group %u cpu %u not possible; cpu is not active (current mask 0x%p)\n",
|
||||
Affinity.wGroup,
|
||||
Affinity.bProc,
|
||||
pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup]._activeProcessorMask);
|
||||
(void *) pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup]._activeProcessorMask);
|
||||
|
||||
fOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ISSUE: many of the following validation errors are stated in cmdline terms, which is not helpful for XML
|
||||
|
||||
if (timeSpan.GetDisableAffinity() && timeSpan.GetAffinityAssignments().size() > 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: -n and -a parameters cannot be used together\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
// ISSUE: with XML and the following the target specification validation it would be useful to say what
|
||||
// target they're for
|
||||
|
||||
for (const auto& target : timeSpan.GetTargets())
|
||||
{
|
||||
const bool targetHasMultipleThreads = (timeSpan.GetThreadCount() > 1) || (target.GetThreadsPerFile() > 1);
|
||||
|
@ -1036,10 +1055,20 @@ bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const
|
|||
}
|
||||
}
|
||||
|
||||
// in the cases where there is only a single configuration specified for each target (e.g., cmdline),
|
||||
// currently there are no validations specific to individual targets (e.g., pre-existing files)
|
||||
// so we can stop validation now. this allows us to only warn/error once, as opposed to repeating
|
||||
// it for each target.
|
||||
// Note that this error is only possible with -f or XML. The -Bbase:length form is immune.
|
||||
if (target.GetMaxFileSize() && target.GetMaxFileSize() <= target.GetBaseFileOffsetInBytes())
|
||||
{
|
||||
fprintf(stderr, "ERROR: maximum (-f) target offset must be greater than base (-B)\n");
|
||||
fOk = false;
|
||||
}
|
||||
|
||||
// If we know there is only a single target specification (the parameters which apply to targets) shared
|
||||
// across the one or more targets, we can stop. In practical terms this is the command line case - for
|
||||
// XML we don't know, and do need to keep going. This early exit lets us avoid repeating the same sets
|
||||
// of error messages per each target we would otherwise loop over.
|
||||
//
|
||||
// If we ever did target property validation (say, v. its size) we'd want to divide out the validations
|
||||
// into parameter-only v. parameter/property cases for similar reasons.
|
||||
if (fSingleSpec)
|
||||
{
|
||||
break;
|
||||
|
|
576
Common/Common.h
576
Common/Common.h
|
@ -30,46 +30,29 @@ SOFTWARE.
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <powersetting.h>
|
||||
#include <powrprof.h>
|
||||
#include <VersionHelpers.h>
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
#include <evntrace.h>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <Winternl.h> //ntdll.dll
|
||||
#include <assert.h>
|
||||
#include "Histogram.h"
|
||||
#include "IoBucketizer.h"
|
||||
#include "ThroughputMeter.h"
|
||||
#include "Version.h"
|
||||
|
||||
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):
|
||||
//
|
||||
// [datetime] "string"
|
||||
//
|
||||
// this should result in a valid System.Datetime object, rendered like:
|
||||
//
|
||||
// Monday, June 16, 2014 12:00:00 AM
|
||||
|
||||
#define DISKSPD_RELEASE_TAG "-dev"
|
||||
#define DISKSPD_REVISION ""
|
||||
|
||||
#define DISKSPD_MAJOR 2
|
||||
#define DISKSPD_MINOR 1
|
||||
#define DISKSPD_BUILD 0
|
||||
#define DISKSPD_QFE 0
|
||||
|
||||
#define DISKSPD_MAJORMINOR_VER_STR(x,y,z) #x "." #y "." #z
|
||||
#define DISKSPD_MAJORMINOR_VERSION_STRING(x,y,z) DISKSPD_MAJORMINOR_VER_STR(x,y,z)
|
||||
#define DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_MAJORMINOR_VERSION_STRING(DISKSPD_MAJOR, DISKSPD_MINOR, DISKSPD_BUILD)
|
||||
|
||||
#define DISKSPD_NUMERIC_VERSION_STRING DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_REVISION DISKSPD_RELEASE_TAG
|
||||
#define DISKSPD_DATE_VERSION_STRING "2021/7/1"
|
||||
|
||||
#define DISKSPD_TRACE_INFO 0x00000000
|
||||
#define DISKSPD_TRACE_RESERVED 0x00000001
|
||||
#define DISKSPD_TRACE_IO 0x00000100
|
||||
|
@ -87,6 +70,9 @@ typedef void (WINAPI *PRINTF)(const char*, va_list);
|
|||
#define MB (((UINT64)1)<<20)
|
||||
#define KB (((UINT64)1)<<10)
|
||||
|
||||
#define EXPERIMENT_TPUT_CALC 0x1 // precise ms sleep calculation for low rate throughput control
|
||||
extern ULONG g_ExperimentFlags;
|
||||
|
||||
struct ETWEventCounters
|
||||
{
|
||||
UINT64 ullIORead; // Read
|
||||
|
@ -401,53 +387,16 @@ public:
|
|||
|
||||
}
|
||||
|
||||
void Add(DWORD dwBytesTransferred,
|
||||
void Add(
|
||||
DWORD dwBytesTransferred,
|
||||
IOOperation type,
|
||||
UINT64 ullIoStartTime,
|
||||
UINT64 ullIoEndTime,
|
||||
UINT64 ullSpanStartTime,
|
||||
bool fMeasureLatency,
|
||||
bool fCalculateIopsStdDev
|
||||
)
|
||||
{
|
||||
double lfDurationUsec = 0;
|
||||
UINT64 ullEndTime = 0;
|
||||
UINT64 ullDuration = 0;
|
||||
|
||||
// assume it is worthwhile to stay off of the time query path unless needed (micro-overhead)
|
||||
if (fMeasureLatency || fCalculateIopsStdDev)
|
||||
{
|
||||
ullEndTime = PerfTimer::GetTime();
|
||||
ullDuration = ullEndTime - ullIoStartTime;
|
||||
lfDurationUsec = PerfTimer::PerfTimeToMicroseconds(ullDuration);
|
||||
}
|
||||
|
||||
if (fMeasureLatency)
|
||||
{
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readLatencyHistogram.Add(static_cast<float>(lfDurationUsec));
|
||||
}
|
||||
else
|
||||
{
|
||||
writeLatencyHistogram.Add(static_cast<float>(lfDurationUsec));
|
||||
}
|
||||
}
|
||||
|
||||
UINT64 ullRelativeCompletionTime = 0;
|
||||
if (fCalculateIopsStdDev)
|
||||
{
|
||||
ullRelativeCompletionTime = ullEndTime - ullSpanStartTime;
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
ullReadBytesCount += dwBytesTransferred; // update read bytes counter
|
||||
|
@ -461,6 +410,44 @@ public:
|
|||
|
||||
ullBytesCount += dwBytesTransferred; // update bytes counter
|
||||
ullIOCount++; // update completed I/O operations counter
|
||||
|
||||
// end time is 0 if we're not measuring latency
|
||||
assert(((fMeasureLatency || fCalculateIopsStdDev) && ullIoEndTime != 0) ||
|
||||
(!fMeasureLatency && !fCalculateIopsStdDev));
|
||||
|
||||
if (ullIoEndTime == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UINT64 ullDuration = ullIoEndTime - ullIoStartTime;;
|
||||
double lfDurationUsec = PerfTimer::PerfTimeToMicroseconds(ullDuration);
|
||||
|
||||
if (fMeasureLatency)
|
||||
{
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readLatencyHistogram.Add(static_cast<float>(lfDurationUsec));
|
||||
}
|
||||
else
|
||||
{
|
||||
writeLatencyHistogram.Add(static_cast<float>(lfDurationUsec));
|
||||
}
|
||||
}
|
||||
|
||||
if (fCalculateIopsStdDev)
|
||||
{
|
||||
UINT64 ullRelativeCompletionTime = ullIoEndTime - ullSpanStartTime;
|
||||
|
||||
if (type == IOOperation::ReadIO)
|
||||
{
|
||||
readBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string sPath;
|
||||
|
@ -482,9 +469,23 @@ public:
|
|||
vector<DistributionRange> vDistributionRange;
|
||||
};
|
||||
|
||||
typedef struct _WAIT_STATS {
|
||||
ULONGLONG Wait;
|
||||
ULONGLONG ThrottleWait;
|
||||
ULONGLONG ThrottleSleep;
|
||||
ULONGLONG Lookaside;
|
||||
ULONGLONG LookasideCompletion[8]; // 0 == none, 1 == 1, ... 7 = 7+
|
||||
} WAIT_STATS;
|
||||
|
||||
class ThreadResults
|
||||
{
|
||||
public:
|
||||
ThreadResults()
|
||||
{
|
||||
WaitStats = { 0 };
|
||||
}
|
||||
|
||||
WAIT_STATS WaitStats;
|
||||
vector<TargetResults> vTargetResults;
|
||||
};
|
||||
|
||||
|
@ -513,73 +514,66 @@ public:
|
|||
|
||||
ProcessorGroupInformation() = delete;
|
||||
ProcessorGroupInformation(
|
||||
WORD Group,
|
||||
BYTE MaximumProcessorCount,
|
||||
BYTE ActiveProcessorCount,
|
||||
WORD Group,
|
||||
KAFFINITY ActiveProcessorMask) :
|
||||
_groupNumber(Group),
|
||||
_maximumProcessorCount(MaximumProcessorCount),
|
||||
_activeProcessorCount(ActiveProcessorCount),
|
||||
_groupNumber(Group),
|
||||
_activeProcessorMask(ActiveProcessorMask)
|
||||
{
|
||||
}
|
||||
|
||||
ProcessorGroupInformation(
|
||||
WORD Group,
|
||||
PROCESSOR_GROUP_INFO& GroupInfo) :
|
||||
_groupNumber(Group),
|
||||
_maximumProcessorCount(GroupInfo.MaximumProcessorCount),
|
||||
_activeProcessorCount(GroupInfo.ActiveProcessorCount),
|
||||
_activeProcessorMask(GroupInfo.ActiveProcessorMask)
|
||||
{
|
||||
}
|
||||
|
||||
// This logic is strictly unaware that sparse processor masks are not possible;
|
||||
// address this later, not important. See comments around RelationGroup query.
|
||||
bool IsProcessorActive(BYTE Processor) const
|
||||
{
|
||||
if (IsProcessorValid(Processor) &&
|
||||
(((KAFFINITY)1 << Processor) & _activeProcessorMask) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (IsProcessorValid(Processor) &&
|
||||
(((KAFFINITY)1 << Processor) & _activeProcessorMask) != 0);
|
||||
}
|
||||
|
||||
bool IsProcessorValid(BYTE Processor) const
|
||||
{
|
||||
if (Processor < _maximumProcessorCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (Processor < _maximumProcessorCount);
|
||||
}
|
||||
};
|
||||
|
||||
class ProcessorNumaInformation
|
||||
{
|
||||
public:
|
||||
DWORD _ulProcCount;
|
||||
DWORD _nodeNumber;
|
||||
WORD _groupNumber;
|
||||
KAFFINITY _processorMask;
|
||||
|
||||
ProcessorNumaInformation() = delete;
|
||||
ProcessorNumaInformation(
|
||||
DWORD Node,
|
||||
WORD Group,
|
||||
KAFFINITY ProcessorMask) :
|
||||
_nodeNumber(Node),
|
||||
_groupNumber(Group),
|
||||
_processorMask(ProcessorMask)
|
||||
{
|
||||
}
|
||||
vector<pair<WORD, KAFFINITY>> _vProcessorMasks;
|
||||
};
|
||||
|
||||
class ProcessorHyperThreadInformation
|
||||
class ProcessorCoreInformation
|
||||
{
|
||||
public:
|
||||
WORD _groupNumber;
|
||||
KAFFINITY _processorMask;
|
||||
BYTE _efficiencyClass;
|
||||
BYTE _groupCoreNumber;
|
||||
|
||||
ProcessorHyperThreadInformation(
|
||||
ProcessorCoreInformation() = delete;
|
||||
ProcessorCoreInformation(
|
||||
WORD Group,
|
||||
KAFFINITY ProcessorMask) :
|
||||
KAFFINITY ProcessorMask,
|
||||
BYTE EfficiencyClass) :
|
||||
_groupNumber(Group),
|
||||
_processorMask(ProcessorMask)
|
||||
_processorMask(ProcessorMask),
|
||||
_efficiencyClass(EfficiencyClass),
|
||||
_groupCoreNumber(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -587,6 +581,8 @@ public:
|
|||
class ProcessorSocketInformation
|
||||
{
|
||||
public:
|
||||
DWORD _ulProcCount;
|
||||
DWORD _ulSocketNumber;
|
||||
vector<pair<WORD, KAFFINITY>> _vProcessorMasks;
|
||||
};
|
||||
|
||||
|
@ -596,10 +592,11 @@ public:
|
|||
vector<ProcessorGroupInformation> _vProcessorGroupInformation;
|
||||
vector<ProcessorNumaInformation> _vProcessorNumaInformation;
|
||||
vector<ProcessorSocketInformation> _vProcessorSocketInformation;
|
||||
vector<ProcessorHyperThreadInformation> _vProcessorHyperThreadInformation;
|
||||
vector<ProcessorCoreInformation> _vProcessorCoreInformation;
|
||||
|
||||
DWORD _ulProcCount;
|
||||
DWORD _ulActiveProcCount;
|
||||
DWORD _ulProcessorCount; // total number of (active) processors
|
||||
BYTE _ubPerformanceEfficiencyClass; // highest performance class present
|
||||
bool _fSMT; // any SMT cores present
|
||||
|
||||
ProcessorTopology()
|
||||
{
|
||||
|
@ -607,8 +604,17 @@ public:
|
|||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pInformation;
|
||||
DWORD AllocSize = 1024;
|
||||
DWORD ReturnedLength = AllocSize;
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP NumaRelation;
|
||||
pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize];
|
||||
|
||||
_ulProcessorCount = 0;
|
||||
_ubPerformanceEfficiencyClass = 0;
|
||||
_fSMT = false;
|
||||
|
||||
////
|
||||
// Group Relations
|
||||
////
|
||||
|
||||
fResult = GetLogicalProcessorInformationEx(RelationGroup, pInformation, &ReturnedLength);
|
||||
if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
|
@ -622,39 +628,73 @@ public:
|
|||
{
|
||||
// Group information comes back as a single (large) element, not an array.
|
||||
assert(ReturnedLength == pInformation->Size);
|
||||
_ulProcCount = 0;
|
||||
_ulActiveProcCount = 0;
|
||||
|
||||
// Fill in group topology vector so we can answer questions about active/max procs
|
||||
//
|
||||
// Fill in group topology vector
|
||||
//
|
||||
// Note: maximum processor count has no utility other than an indication of the
|
||||
// bit width of the KAFFINITY mask that might have set values. But:
|
||||
//
|
||||
// 1) any mask will be a contiguous run of set bits (no sparse holes); there is
|
||||
// no case where a 0 bit will be present to indicate a gap/disabled processor
|
||||
// 2) all system APIs (such as the cpu utilization query) are defined over active
|
||||
// processors
|
||||
//
|
||||
// There are (new?) cases where maximum is represented as > active on large systems,
|
||||
// which makes these distinctions critical... active processor count is the only
|
||||
// count that matters.
|
||||
//
|
||||
// For the sake of documentation we do save & report out the masks as reported by the
|
||||
// system, but the only ones we look at are limited to cases where we get information
|
||||
// in the form of GROUP_AFFINITY, which is just group # and mask (like NUMA and package
|
||||
// association).
|
||||
//
|
||||
|
||||
for (WORD i = 0; i < pInformation->Group.ActiveGroupCount; i++)
|
||||
{
|
||||
_vProcessorGroupInformation.emplace_back(
|
||||
pInformation->Group.GroupInfo[i].MaximumProcessorCount,
|
||||
pInformation->Group.GroupInfo[i].ActiveProcessorCount,
|
||||
i,
|
||||
pInformation->Group.GroupInfo[i].ActiveProcessorMask
|
||||
pInformation->Group.GroupInfo[i]
|
||||
);
|
||||
_ulProcCount += _vProcessorGroupInformation[i]._maximumProcessorCount;
|
||||
_ulActiveProcCount += _vProcessorGroupInformation[i]._activeProcessorCount;
|
||||
|
||||
_ulProcessorCount += _vProcessorGroupInformation[i]._activeProcessorCount;
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
// NUMA Relations
|
||||
////
|
||||
|
||||
//
|
||||
// Dynamically detect the available NUMA relations. Non-Ex returns exactly one relation and
|
||||
// does not define the GroupCount field. Ex scales to return multiple groups for large systems
|
||||
// with > 64 per NUMA domain and does populate GroupCount.
|
||||
//
|
||||
|
||||
NumaRelation = RelationNumaNodeEx;
|
||||
ReturnedLength = AllocSize;
|
||||
fResult = GetLogicalProcessorInformationEx(RelationNumaNode, pInformation, &ReturnedLength);
|
||||
fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength);
|
||||
if (!fResult && GetLastError() == ERROR_GEN_FAILURE)
|
||||
{
|
||||
NumaRelation = RelationNumaNode;
|
||||
fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength);
|
||||
}
|
||||
if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
delete [] pInformation;
|
||||
AllocSize = ReturnedLength;
|
||||
pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize];
|
||||
fResult = GetLogicalProcessorInformationEx(RelationNumaNode, pInformation, &ReturnedLength);
|
||||
fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength);
|
||||
}
|
||||
|
||||
if (fResult)
|
||||
{
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation;
|
||||
|
||||
while (ReturnedLength != 0)
|
||||
while (ReturnedLength > 0)
|
||||
{
|
||||
ProcessorNumaInformation node;
|
||||
|
||||
assert(ReturnedLength >= cur->Size);
|
||||
|
||||
if (cur->Size > ReturnedLength)
|
||||
|
@ -662,17 +702,26 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
_vProcessorNumaInformation.emplace_back(
|
||||
cur->NumaNode.NodeNumber,
|
||||
cur->NumaNode.GroupMask.Group,
|
||||
cur->NumaNode.GroupMask.Mask
|
||||
);
|
||||
node._nodeNumber = cur->NumaNode.NodeNumber;
|
||||
node._ulProcCount = 0;
|
||||
for (WORD i = 0; i < (NumaRelation == RelationNumaNode ? 1 : cur->NumaNode.GroupCount); i++)
|
||||
{
|
||||
node._ulProcCount += ProcessorTopology::MaskCount(cur->NumaNode.GroupMasks[i].Mask);
|
||||
node._vProcessorMasks.emplace_back(cur->NumaNode.GroupMasks[i].Group,
|
||||
cur->NumaNode.GroupMasks[i].Mask);
|
||||
}
|
||||
|
||||
_vProcessorNumaInformation.push_back(node);
|
||||
|
||||
ReturnedLength -= cur->Size;
|
||||
cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size);
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
// Socket/Package Relations
|
||||
////
|
||||
|
||||
ReturnedLength = AllocSize;
|
||||
fResult = GetLogicalProcessorInformationEx(RelationProcessorPackage, pInformation, &ReturnedLength);
|
||||
if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
|
@ -687,6 +736,7 @@ public:
|
|||
{
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation;
|
||||
|
||||
DWORD socketNumber = 0;
|
||||
while (ReturnedLength != 0)
|
||||
{
|
||||
ProcessorSocketInformation socket;
|
||||
|
@ -698,8 +748,11 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
for (WORD i = 0; i < pInformation->Processor.GroupCount; i++)
|
||||
socket._ulProcCount = 0;
|
||||
socket._ulSocketNumber = socketNumber;
|
||||
for (WORD i = 0; i < cur->Processor.GroupCount; i++)
|
||||
{
|
||||
socket._ulProcCount += ProcessorTopology::MaskCount(cur->Processor.GroupMask[i].Mask);
|
||||
socket._vProcessorMasks.emplace_back(cur->Processor.GroupMask[i].Group,
|
||||
cur->Processor.GroupMask[i].Mask);
|
||||
}
|
||||
|
@ -708,9 +761,14 @@ public:
|
|||
|
||||
ReturnedLength -= cur->Size;
|
||||
cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size);
|
||||
socketNumber += 1;
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
// Core Relations
|
||||
////
|
||||
|
||||
ReturnedLength = AllocSize;
|
||||
fResult = GetLogicalProcessorInformationEx(RelationProcessorCore, pInformation, &ReturnedLength);
|
||||
if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
|
@ -721,9 +779,20 @@ public:
|
|||
fResult = GetLogicalProcessorInformationEx(RelationProcessorCore, pInformation, &ReturnedLength);
|
||||
}
|
||||
|
||||
//
|
||||
// The EfficiencyClass member was added with Windows 10
|
||||
//
|
||||
|
||||
BOOL fEfficiencyClass = false;
|
||||
if (IsWindows10OrGreater())
|
||||
{
|
||||
fEfficiencyClass = true;
|
||||
}
|
||||
|
||||
if (fResult)
|
||||
{
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation;
|
||||
BYTE curEfficiency;
|
||||
|
||||
while (ReturnedLength != 0)
|
||||
{
|
||||
|
@ -734,14 +803,57 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the highest performance core class and presence of SMT as we sweep.
|
||||
// Note that SMT is per core and can be asymmetric.
|
||||
//
|
||||
|
||||
if (fEfficiencyClass)
|
||||
{
|
||||
curEfficiency = cur->Processor.EfficiencyClass;
|
||||
if (_ubPerformanceEfficiencyClass < curEfficiency)
|
||||
{
|
||||
_ubPerformanceEfficiencyClass = curEfficiency;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->Processor.Flags & LTP_PC_SMT)
|
||||
{
|
||||
_fSMT = true;
|
||||
}
|
||||
|
||||
assert(pInformation->Processor.GroupCount == 1);
|
||||
|
||||
_vProcessorHyperThreadInformation.emplace_back(cur->Processor.GroupMask[0].Group,
|
||||
cur->Processor.GroupMask[0].Mask);
|
||||
_vProcessorCoreInformation.emplace_back(cur->Processor.GroupMask[0].Group,
|
||||
cur->Processor.GroupMask[0].Mask,
|
||||
fEfficiencyClass ? cur->Processor.EfficiencyClass : (BYTE)0);
|
||||
|
||||
ReturnedLength -= cur->Size;
|
||||
cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size);
|
||||
}
|
||||
|
||||
// Now guarantee ascending order of group number & cpu mask so that group-relative core number can be assigned
|
||||
|
||||
sort(_vProcessorCoreInformation.begin(), _vProcessorCoreInformation.end(),
|
||||
[](const ProcessorCoreInformation& a, const ProcessorCoreInformation& b)
|
||||
{
|
||||
return a._groupNumber < b._groupNumber ||
|
||||
(a._groupNumber == b._groupNumber && a._processorMask < b._processorMask);
|
||||
});
|
||||
|
||||
// Assign group-relative core number
|
||||
|
||||
BYTE coreNumber = 0;
|
||||
WORD group = 0;
|
||||
for (auto& core : _vProcessorCoreInformation)
|
||||
{
|
||||
if (core._groupNumber != group)
|
||||
{
|
||||
group = core._groupNumber;
|
||||
coreNumber = 0;
|
||||
}
|
||||
core._groupCoreNumber = coreNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get the cache relationships as well???
|
||||
|
@ -765,6 +877,9 @@ public:
|
|||
// or inclusive (Next = false) of the input group/processor.
|
||||
// Iteration is in order of absolute processor number.
|
||||
// This does assume at least one core is active, but that is a given.
|
||||
//
|
||||
// This logic is strictly unaware that sparse processor masks are not possible;
|
||||
// address this later, not important. See comments around RelationGroup query.
|
||||
void GetActiveGroupProcessor(WORD& Group, BYTE& Processor, bool Next)
|
||||
{
|
||||
if (Next)
|
||||
|
@ -788,6 +903,79 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Efficiency of these mappings is not a first order concern. We simply use these to avoid assuming
|
||||
// ordering of groups/masks of processors within topology structures. There's strictly no reason,
|
||||
// for example, that socket 0 contains the first groups (0, 1, etc.) of processors, at least not
|
||||
// documented or guaranteed.
|
||||
//
|
||||
|
||||
DWORD GetNumaOfProcessor(WORD Group, BYTE Processor) const
|
||||
{
|
||||
for (const auto& numa : _vProcessorNumaInformation)
|
||||
{
|
||||
for (const auto& mask : numa._vProcessorMasks)
|
||||
{
|
||||
if (mask.first == Group && (mask.second & ((KAFFINITY)1 << Processor)))
|
||||
{
|
||||
return numa._nodeNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD GetSocketOfProcessor(WORD Group, BYTE Processor) const
|
||||
{
|
||||
for (const auto& socket : _vProcessorSocketInformation)
|
||||
{
|
||||
for (const auto& mask : socket._vProcessorMasks)
|
||||
{
|
||||
if (mask.first == Group && (mask.second & ((KAFFINITY)1 << Processor)))
|
||||
{
|
||||
return socket._ulSocketNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE GetCoreOfProcessor(WORD Group, BYTE Processor, BYTE& EfficiencyClass) const
|
||||
{
|
||||
for (const auto& core : _vProcessorCoreInformation)
|
||||
{
|
||||
if (core._groupNumber == Group && (core._processorMask & ((KAFFINITY)1 << Processor)))
|
||||
{
|
||||
EfficiencyClass = core._efficiencyClass;
|
||||
return core._groupCoreNumber;
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int MaskCount(KAFFINITY Mask)
|
||||
{
|
||||
//
|
||||
// Trivial popcount for affinity mask w/o insn dependency
|
||||
//
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
while (Mask)
|
||||
{
|
||||
Mask &= (Mask - 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -801,7 +989,7 @@ public:
|
|||
// start new indented section
|
||||
#define AddXmlInc(s,str) { (s).append(indent, ' '); indent += 2; (s) += (str); }
|
||||
// end indented section
|
||||
#define AddXmlDec(s,str) { indent -= 2; (s).append(indent, ' '); (s) += (str); }
|
||||
#define AddXmlDec(s,str) { if (indent >= 2) { indent -= 2; }; (s).append(indent, ' '); (s) += (str); }
|
||||
|
||||
class SystemInformation
|
||||
{
|
||||
|
@ -809,14 +997,16 @@ private:
|
|||
SYSTEMTIME StartTime;
|
||||
|
||||
public:
|
||||
string sComputerName;
|
||||
ProcessorTopology processorTopology;
|
||||
string sComputerName;
|
||||
string sActivePolicyName;
|
||||
string sActivePolicyGuid;
|
||||
|
||||
SystemInformation()
|
||||
{
|
||||
// System Name
|
||||
char buffer[64];
|
||||
char buffer[128];
|
||||
DWORD cb = _countof(buffer);
|
||||
GUID *guid = NULL;
|
||||
BOOL fResult;
|
||||
|
||||
#pragma prefast(suppress:38020, "Yes, we're aware this is an ANSI API in a UNICODE project")
|
||||
|
@ -828,6 +1018,52 @@ public:
|
|||
|
||||
// capture start time
|
||||
GetSystemTime(&StartTime);
|
||||
|
||||
if (PowerGetActiveScheme(NULL, &guid) == ERROR_SUCCESS &&
|
||||
PowerReadFriendlyName(NULL, guid, NULL, NULL, NULL, &cb) == ERROR_SUCCESS)
|
||||
{
|
||||
PUCHAR pwrBuffer;
|
||||
|
||||
if (cb <= _countof(buffer))
|
||||
{
|
||||
pwrBuffer = (PUCHAR) buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
pwrBuffer = new UCHAR[cb];
|
||||
}
|
||||
|
||||
if (PowerReadFriendlyName(NULL, guid, NULL, NULL, pwrBuffer, &cb) == ERROR_SUCCESS)
|
||||
{
|
||||
// Cast wide string down to basic - all of our current output streams are basic
|
||||
wstring wActivePolicyName = (PWCHAR) pwrBuffer;
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> cvt;
|
||||
sActivePolicyName = cvt.to_bytes(wActivePolicyName);
|
||||
}
|
||||
|
||||
if (pwrBuffer != (PVOID) buffer)
|
||||
{
|
||||
delete pwrBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (sActivePolicyName.empty())
|
||||
{
|
||||
sActivePolicyName = "<unknown>";
|
||||
}
|
||||
|
||||
if (guid)
|
||||
{
|
||||
sprintf_s(buffer, _countof(buffer),
|
||||
"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
|
||||
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
|
||||
|
||||
sActivePolicyGuid = buffer;
|
||||
|
||||
LocalFree(guid);
|
||||
}
|
||||
}
|
||||
|
||||
// for unit test, squelch variable timestamp
|
||||
|
@ -838,7 +1074,7 @@ public:
|
|||
|
||||
string SystemInformation::GetText() const
|
||||
{
|
||||
char szBuffer[64]; // enough for 64bit mask (17ch) and timestamp
|
||||
char szBuffer[128]; // guid (36ch), timestamp and power friendly (up to 64ch)
|
||||
int nWritten;
|
||||
string sText("System information:\n\n");
|
||||
|
||||
|
@ -862,6 +1098,31 @@ public:
|
|||
sText += szBuffer;
|
||||
}
|
||||
|
||||
sText += "\n\n\tcpu count:\t\t";
|
||||
sText += to_string(processorTopology._ulProcessorCount);
|
||||
sText += "\n\tcore count:\t\t";
|
||||
sText += to_string(processorTopology._vProcessorCoreInformation.size());
|
||||
sText += "\n\tgroup count:\t\t";
|
||||
sText += to_string(processorTopology._vProcessorGroupInformation.size());
|
||||
sText += "\n\tnode count:\t\t";
|
||||
sText += to_string(processorTopology._vProcessorNumaInformation.size());
|
||||
sText += "\n\tsocket count:\t\t";
|
||||
sText += to_string(processorTopology._vProcessorSocketInformation.size());
|
||||
sText += "\n\theterogeneous cores:\t";
|
||||
sText += processorTopology._ubPerformanceEfficiencyClass ? "y\n" : "n\n";
|
||||
|
||||
sText += "\n\tactive power scheme:\t";
|
||||
sText += sActivePolicyName;
|
||||
|
||||
if (!sActivePolicyGuid.empty())
|
||||
{
|
||||
sText += " (";
|
||||
sText += sActivePolicyGuid;
|
||||
sText += ")";
|
||||
}
|
||||
|
||||
sText += "\n";
|
||||
|
||||
return sText;
|
||||
}
|
||||
|
||||
|
@ -900,8 +1161,16 @@ public:
|
|||
}
|
||||
sXml += "</RunTime>\n";
|
||||
|
||||
AddXml(sXml, "<PowerScheme Name=\"")
|
||||
sXml += sActivePolicyName;
|
||||
sXml += "\" Guid=\"";
|
||||
sXml += sActivePolicyGuid;
|
||||
sXml += "\"/>\n";
|
||||
|
||||
// processor topology
|
||||
AddXmlInc(sXml, "<ProcessorTopology>\n");
|
||||
AddXmlInc(sXml, "<ProcessorTopology Heterogeneous=\"");
|
||||
sXml += processorTopology._ubPerformanceEfficiencyClass ? "true\">\n" : "false\">\n";
|
||||
|
||||
for (const auto& g : processorTopology._vProcessorGroupInformation)
|
||||
{
|
||||
AddXml(sXml, "<Group Group=\"");
|
||||
|
@ -919,24 +1188,31 @@ public:
|
|||
}
|
||||
for (const auto& n : processorTopology._vProcessorNumaInformation)
|
||||
{
|
||||
AddXml(sXml, "<Node Node=\"");
|
||||
AddXmlInc(sXml, "<Node Node=\"");
|
||||
sXml += to_string(n._nodeNumber);
|
||||
sXml += "\" Group=\"";
|
||||
sXml += to_string(n._groupNumber);
|
||||
sXml += "\" Processors=\"0x";
|
||||
nWritten = sprintf_s(szBuffer, _countof(szBuffer), "%Ix", n._processorMask);
|
||||
sXml += "\">\n";
|
||||
for (const auto& g : n._vProcessorMasks)
|
||||
{
|
||||
AddXml(sXml, "<Group Group=\"");
|
||||
sXml += to_string(g.first);
|
||||
sXml += "\" Mask=\"0x";
|
||||
nWritten = sprintf_s(szBuffer, _countof(szBuffer), "%Ix", g.second);
|
||||
assert(nWritten && nWritten < _countof(szBuffer));
|
||||
sXml += szBuffer;
|
||||
sXml += "\"/>\n";
|
||||
}
|
||||
AddXmlDec(sXml, "</Node>\n");
|
||||
}
|
||||
for (const auto& s : processorTopology._vProcessorSocketInformation)
|
||||
{
|
||||
AddXmlInc(sXml, "<Socket>\n");
|
||||
AddXmlInc(sXml, "<Socket Socket=\"");
|
||||
sXml += to_string(s._ulSocketNumber);
|
||||
sXml += "\">\n";
|
||||
for (const auto& g : s._vProcessorMasks)
|
||||
{
|
||||
AddXml(sXml, "<Group Group=\"");
|
||||
sXml += to_string(g.first);
|
||||
sXml += "\" Processors=\"0x";
|
||||
sXml += "\" Mask=\"0x";
|
||||
nWritten = sprintf_s(szBuffer, _countof(szBuffer), "%Ix", g.second);
|
||||
assert(nWritten && nWritten < _countof(szBuffer));
|
||||
sXml += szBuffer;
|
||||
|
@ -944,14 +1220,18 @@ public:
|
|||
}
|
||||
AddXmlDec(sXml, "</Socket>\n");
|
||||
}
|
||||
for (const auto& h : processorTopology._vProcessorHyperThreadInformation)
|
||||
for (const auto& h : processorTopology._vProcessorCoreInformation)
|
||||
{
|
||||
AddXml(sXml, "<HyperThread Group=\"");
|
||||
AddXml(sXml, "<Core Group=\"");
|
||||
sXml += to_string(h._groupNumber);
|
||||
sXml += "\" Processors=\"0x";
|
||||
sXml += "\" Core=\"";
|
||||
sXml += to_string(h._groupCoreNumber);
|
||||
sXml += "\" Mask=\"0x";
|
||||
nWritten = sprintf_s(szBuffer, _countof(szBuffer), "%Ix", h._processorMask);
|
||||
assert(nWritten && nWritten < _countof(szBuffer));
|
||||
sXml += szBuffer;
|
||||
sXml += "\" EfficiencyClass=\"";
|
||||
sXml += to_string(h._efficiencyClass);
|
||||
sXml += "\"/>\n";
|
||||
}
|
||||
|
||||
|
@ -1532,6 +1812,7 @@ public:
|
|||
Profile() :
|
||||
_fProfileOnly(false),
|
||||
_fVerbose(false),
|
||||
_fVerboseStats(false),
|
||||
_dwProgress(0),
|
||||
_fEtwEnabled(false),
|
||||
_fEtwProcess(false),
|
||||
|
@ -1569,6 +1850,9 @@ public:
|
|||
void SetVerbose(bool b) { _fVerbose = b; }
|
||||
bool GetVerbose() const { return _fVerbose; }
|
||||
|
||||
void SetVerboseStats(bool b) { _fVerboseStats = b; }
|
||||
bool GetVerboseStats() const { return _fVerboseStats; }
|
||||
|
||||
void SetProgress(DWORD dwProgress) { _dwProgress = dwProgress; }
|
||||
DWORD GetProgress() const { return _dwProgress; }
|
||||
|
||||
|
@ -1619,6 +1903,7 @@ private:
|
|||
|
||||
vector<TimeSpan>_vTimeSpans;
|
||||
bool _fVerbose;
|
||||
bool _fVerboseStats;
|
||||
bool _fProfileOnly;
|
||||
DWORD _dwProgress;
|
||||
string _sCmdLine;
|
||||
|
@ -1649,7 +1934,7 @@ public:
|
|||
IORequest(Random *pRand) :
|
||||
_ioType(IOOperation::ReadIO),
|
||||
_pRand(pRand),
|
||||
_pCurrentTarget(nullptr),
|
||||
_iCurrentTarget(0),
|
||||
_ullStartTime(0),
|
||||
_ulRequestIndex(0xFFFFFFFF),
|
||||
_ullTotalWeight(0),
|
||||
|
@ -1677,24 +1962,25 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Target *GetCurrentTarget() { return _pCurrentTarget; }
|
||||
Target *GetCurrentTarget() { return _vTargets[_iCurrentTarget]; }
|
||||
size_t GetCurrentTargetIndex() { return _iCurrentTarget; }
|
||||
|
||||
Target *GetNextTarget()
|
||||
{
|
||||
UINT64 ullWeight;
|
||||
|
||||
if (_vTargets.size() == 1) {
|
||||
_pCurrentTarget = _vTargets[0];
|
||||
_iCurrentTarget = 0;
|
||||
}
|
||||
else if (_fEqualWeights) {
|
||||
_pCurrentTarget = _vTargets[_pRand->Rand32() % _vTargets.size()];
|
||||
_iCurrentTarget = _pRand->Rand32() % _vTargets.size();
|
||||
}
|
||||
else {
|
||||
ullWeight = _pRand->Rand64() % _ullTotalWeight;
|
||||
|
||||
for (size_t iTarget = 0; iTarget < _vTargets.size(); iTarget++) {
|
||||
if (ullWeight < _vulTargetWeights[iTarget]) {
|
||||
_pCurrentTarget = _vTargets[iTarget];
|
||||
_iCurrentTarget = iTarget;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1702,7 +1988,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
return _pCurrentTarget;
|
||||
return GetCurrentTarget();
|
||||
}
|
||||
|
||||
void SetIoType(IOOperation ioType) { _ioType = ioType; }
|
||||
|
@ -1724,7 +2010,7 @@ private:
|
|||
UINT64 _ullTotalWeight;
|
||||
bool _fEqualWeights;
|
||||
Random *_pRand;
|
||||
Target *_pCurrentTarget;
|
||||
size_t _iCurrentTarget;
|
||||
IOOperation _ioType;
|
||||
UINT64 _ullStartTime;
|
||||
UINT32 _ulRequestIndex;
|
||||
|
|
|
@ -36,6 +36,8 @@ SOFTWARE.
|
|||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
// Plain min/max macros from common headers will interfere with std::numeric_limits
|
||||
|
||||
#pragma push_macro("min")
|
||||
#pragma push_macro("max")
|
||||
#undef min
|
||||
|
@ -46,34 +48,54 @@ class Histogram
|
|||
{
|
||||
private:
|
||||
|
||||
unsigned _samples;
|
||||
mutable std::unordered_map<T, unsigned> _data;
|
||||
mutable unsigned _samples;
|
||||
|
||||
#define USE_HASH_TABLE
|
||||
#ifdef USE_HASH_TABLE
|
||||
std::unordered_map<T,unsigned> _data;
|
||||
mutable std::map<T, unsigned> _sdata;
|
||||
mutable unsigned _ssamples;
|
||||
|
||||
std::map<T,unsigned> _GetSortedData() const
|
||||
// Save most recent percentile/iterator/nth-distance query. If the next is strictly >= it allows
|
||||
// an efficient forward iteration through an ascending set of queries.
|
||||
|
||||
mutable double _lastptile;
|
||||
mutable unsigned _lastptilen;
|
||||
mutable decltype(_sdata.cbegin()) _lastptilepos;
|
||||
|
||||
// A histogram starts writable/unsealed and automatically seals after the first read operation.
|
||||
// Subsequent writes which add data restart from empty.
|
||||
|
||||
void _SealData() const
|
||||
{
|
||||
return std::map<T,unsigned>(_data.begin(), _data.end());
|
||||
}
|
||||
#else
|
||||
std::map<T,unsigned> _data;
|
||||
|
||||
std::map<T,unsigned> _GetSortedData() const
|
||||
if (!_data.empty())
|
||||
{
|
||||
return _data;
|
||||
_sdata.clear();
|
||||
|
||||
_sdata = std::map<T, unsigned>(_data.cbegin(), _data.cend());
|
||||
_ssamples = _samples;
|
||||
|
||||
// invalid ptile > 1; first ptile query will initialize
|
||||
_lastptile = 1.1;
|
||||
|
||||
_data.clear();
|
||||
_samples = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Histogram()
|
||||
: _samples(0)
|
||||
: _samples(0),
|
||||
_ssamples(0)
|
||||
{}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
_data.clear();
|
||||
_samples = 0;
|
||||
|
||||
_sdata.clear();
|
||||
_ssamples = 0;
|
||||
|
||||
}
|
||||
|
||||
void Add(T v)
|
||||
|
@ -94,63 +116,86 @@ class Histogram
|
|||
|
||||
T GetMin() const
|
||||
{
|
||||
T min(std::numeric_limits<T>::max());
|
||||
_SealData();
|
||||
|
||||
for (auto i : _data)
|
||||
// Default low if empty
|
||||
if (!_ssamples)
|
||||
{
|
||||
if (i.first < min)
|
||||
{
|
||||
min = i.first;
|
||||
}
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
return min;
|
||||
return _sdata.cbegin()->first;
|
||||
}
|
||||
|
||||
T GetMax() const
|
||||
{
|
||||
T max(std::numeric_limits<T>::min());
|
||||
_SealData();
|
||||
|
||||
for (auto i : _data)
|
||||
// Default low if empty
|
||||
if (!_ssamples)
|
||||
{
|
||||
if (i.first > max)
|
||||
{
|
||||
max = i.first;
|
||||
}
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
return max;
|
||||
return _sdata.crbegin()->first;
|
||||
}
|
||||
|
||||
unsigned GetSampleBuckets() const
|
||||
{
|
||||
return (unsigned) (_samples ? _data.size() : _sdata.size());
|
||||
}
|
||||
|
||||
unsigned GetSampleSize() const
|
||||
{
|
||||
return _samples;
|
||||
return _samples ? _samples : _ssamples;
|
||||
}
|
||||
|
||||
T GetPercentile(double p) const
|
||||
{
|
||||
// ISSUE-REVIEW
|
||||
// What do the 0th and 100th percentile really mean?
|
||||
if ((p < 0) || (p > 1))
|
||||
if ((p < 0.0) || (p > 1.0))
|
||||
{
|
||||
throw std::invalid_argument("Percentile must be >= 0 and <= 1");
|
||||
}
|
||||
|
||||
const double target = GetSampleSize() * p;
|
||||
_SealData();
|
||||
|
||||
unsigned cur = 0;
|
||||
for (auto i : _GetSortedData())
|
||||
// Default low if empty
|
||||
if (!_ssamples)
|
||||
{
|
||||
cur += i.second;
|
||||
if (cur >= target)
|
||||
{
|
||||
return i.first;
|
||||
}
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
// We can get here if no IOs are issued, simply return 0 since
|
||||
// we don't want to throw an exception and crash
|
||||
return 0;
|
||||
const double target = p * _ssamples;
|
||||
|
||||
// Default to beginning; n is the number of samples iterated over so far
|
||||
unsigned n = 0;
|
||||
auto pos = _sdata.cbegin();
|
||||
|
||||
// Resume from last?
|
||||
if (p >= _lastptile)
|
||||
{
|
||||
n = _lastptilen;
|
||||
pos = _lastptilepos;
|
||||
}
|
||||
|
||||
while (pos != _sdata.cend())
|
||||
{
|
||||
if (n + pos->second >= target)
|
||||
{
|
||||
// Save position. Note the pre-incremented distance through the histogram
|
||||
// must be saved in case next is still in the same bucket.
|
||||
_lastptile = p;
|
||||
_lastptilen = n;
|
||||
_lastptilepos = pos;
|
||||
|
||||
return pos->first;
|
||||
}
|
||||
|
||||
n += pos->second;
|
||||
++pos;
|
||||
}
|
||||
|
||||
throw std::overflow_error("overran end trying to find percentile");
|
||||
}
|
||||
|
||||
T GetPercentile(int p) const
|
||||
|
@ -168,13 +213,20 @@ class Histogram
|
|||
|
||||
double GetMean() const
|
||||
{
|
||||
double sum(0);
|
||||
unsigned samples = GetSampleSize();
|
||||
_SealData();
|
||||
|
||||
for (auto i : _data)
|
||||
// Default low if empty
|
||||
if (!_ssamples)
|
||||
{
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
double sum(0);
|
||||
|
||||
for (const auto i : _sdata)
|
||||
{
|
||||
double bucket_val =
|
||||
static_cast<double>(i.first) * i.second / samples;
|
||||
static_cast<double>(i.first) * i.second / _ssamples;
|
||||
|
||||
if (sum + bucket_val < 0)
|
||||
{
|
||||
|
@ -192,14 +244,14 @@ class Histogram
|
|||
double mean(GetMean());
|
||||
double ssd(0);
|
||||
|
||||
for (auto i : _data)
|
||||
for (const auto i : _sdata)
|
||||
{
|
||||
double dev = static_cast<double>(i.first) - mean;
|
||||
double sqdev = dev * dev;
|
||||
ssd += i.second * sqdev;
|
||||
}
|
||||
|
||||
return sqrt(ssd / GetSampleSize());
|
||||
return sqrt(ssd / _ssamples);
|
||||
}
|
||||
|
||||
std::string GetHistogramCsv(const unsigned bins) const
|
||||
|
@ -209,6 +261,8 @@ class Histogram
|
|||
|
||||
std::string GetHistogramCsv(const unsigned bins, const T LOW, const T HIGH) const
|
||||
{
|
||||
_SealData();
|
||||
|
||||
// ISSUE-REVIEW
|
||||
// Currently bins are defined as strictly less-than
|
||||
// their upper limit, with the exception of the last
|
||||
|
@ -219,10 +273,7 @@ class Histogram
|
|||
std::ostringstream os;
|
||||
os.precision(std::numeric_limits<T>::digits10);
|
||||
|
||||
std::map<T,unsigned> sortedData = _GetSortedData();
|
||||
|
||||
auto pos = sortedData.begin();
|
||||
|
||||
auto pos = _sdata.cbegin();
|
||||
unsigned cumulative = 0;
|
||||
|
||||
for (unsigned bin = 1; bin <= bins; ++bin)
|
||||
|
@ -230,7 +281,7 @@ class Histogram
|
|||
unsigned count = 0;
|
||||
limit += binSize;
|
||||
|
||||
while (pos != sortedData.end() &&
|
||||
while (pos != _sdata.end() &&
|
||||
(pos->first < limit || bin == bins))
|
||||
{
|
||||
count += pos->second;
|
||||
|
@ -247,10 +298,12 @@ class Histogram
|
|||
|
||||
std::string GetRawCsv() const
|
||||
{
|
||||
_SealData();
|
||||
|
||||
std::ostringstream os;
|
||||
os.precision(std::numeric_limits<T>::digits10);
|
||||
|
||||
for (auto i : _GetSortedData())
|
||||
for (const auto i : _sdata)
|
||||
{
|
||||
os << i.first << "," << i.second << std::endl;
|
||||
}
|
||||
|
@ -260,9 +313,11 @@ class Histogram
|
|||
|
||||
std::string GetRaw() const
|
||||
{
|
||||
_SealData();
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
for (auto i : _GetSortedData())
|
||||
for (const auto i : _sdata)
|
||||
{
|
||||
os << i.second << " " << i.first << std::endl;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ private:
|
|||
bool _CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const;
|
||||
bool _GetActiveGroupsAndProcs() const;
|
||||
struct ETWSessionInfo _GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const;
|
||||
bool _GetSystemPerfInfo(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pInfo, UINT32 uCpuCount) const;
|
||||
bool _GetSystemPerfInfo(vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION>& vSPPI, bool fVerbose) const;
|
||||
void _InitializeGlobalParameters();
|
||||
bool _LoadDLLs();
|
||||
bool _StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const;
|
||||
|
|
|
@ -61,6 +61,7 @@ private:
|
|||
void _PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fUseRequestsPerFile, bool fCompletionRoutines);
|
||||
void _PrintDistribution(DistributionType dT, const vector<DistributionRange>& v, char* spc);
|
||||
void _PrintEffectiveDistributions(const Results& results);
|
||||
void _PrintWaitStats(const Results& result);
|
||||
|
||||
string _sResult;
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
|
||||
DISKSPD
|
||||
|
||||
Copyright(c) Microsoft Corporation
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// versioning material. for simplicity in consumption, please ensure that the date string
|
||||
// parses via the System.Datetime constructor as follows (in Powershell):
|
||||
//
|
||||
// [datetime] "string"
|
||||
//
|
||||
// this should result in a valid System.Datetime object, rendered like:
|
||||
//
|
||||
// Monday, June 16, 2014 12:00:00 AM
|
||||
|
||||
#define DISKSPD_RELEASE_TAG ""
|
||||
#define DISKSPD_REVISION ""
|
||||
|
||||
#define DISKSPD_MAJOR 2
|
||||
#define DISKSPD_MINOR 2
|
||||
#define DISKSPD_BUILD 0
|
||||
#define DISKSPD_QFE 0
|
||||
|
||||
#define DISKSPD_MAJORMINOR_VER_STR(x,y,z) #x "." #y "." #z
|
||||
#define DISKSPD_MAJORMINOR_VERSION_STRING(x,y,z) DISKSPD_MAJORMINOR_VER_STR(x,y,z)
|
||||
#define DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_MAJORMINOR_VERSION_STRING(DISKSPD_MAJOR, DISKSPD_MINOR, DISKSPD_BUILD)
|
||||
|
||||
#define DISKSPD_NUMERIC_VERSION_STRING DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_REVISION DISKSPD_RELEASE_TAG
|
||||
#define DISKSPD_DATE_VERSION_STRING "2024/6/3"
|
|
@ -46,7 +46,9 @@ private:
|
|||
void _PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs);
|
||||
void _PrintOverallIops(const Results& results, UINT32 bucketTimeInMs);
|
||||
void _PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs);
|
||||
void _PrintWaitStats(const ThreadResults& threadResult);
|
||||
|
||||
void _PrintV(const char *format, va_list listArg);
|
||||
void _Print(const char *format, ...);
|
||||
void _PrintInc(const char *format, ...);
|
||||
void _PrintDec(const char *format, ...);
|
||||
|
|
|
@ -437,7 +437,7 @@ __declspec(align(4)) static LONG volatile g_lGeneratorRunning = 0; //used to de
|
|||
|
||||
static BOOL volatile g_bError = FALSE; //true means there was fatal error during intialization and threads shouldn't perform their work
|
||||
|
||||
VOID SetProcGroupMask(WORD wGroupNum, DWORD dwProcNum, PGROUP_AFFINITY pGroupAffinity)
|
||||
VOID SetProcGroupMask(WORD wGroupNum, ULONG dwProcNum, PGROUP_AFFINITY pGroupAffinity)
|
||||
{
|
||||
//must zero this structure first, otherwise it fails to set affinity
|
||||
memset(pGroupAffinity, 0, sizeof(GROUP_AFFINITY));
|
||||
|
@ -446,6 +446,15 @@ VOID SetProcGroupMask(WORD wGroupNum, DWORD dwProcNum, PGROUP_AFFINITY pGroupAff
|
|||
pGroupAffinity->Mask = (KAFFINITY)1<<dwProcNum;
|
||||
}
|
||||
|
||||
VOID SetGroupMask(WORD wGroupNum, KAFFINITY Mask, PGROUP_AFFINITY pGroupAffinity)
|
||||
{
|
||||
//must zero this structure first, otherwise it fails to set affinity
|
||||
memset(pGroupAffinity, 0, sizeof(GROUP_AFFINITY));
|
||||
|
||||
pGroupAffinity->Group = wGroupNum;
|
||||
pGroupAffinity->Mask = Mask;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void IORequestGenerator::_CloseOpenFiles(vector<HANDLE>& vhFiles) const
|
||||
{
|
||||
|
@ -483,6 +492,29 @@ static void PrintVerbose(bool fVerbose, const char *format, ...)
|
|||
|
||||
if(fVerbose )
|
||||
{
|
||||
SYSTEMTIME now;
|
||||
char szBuffer[64]; // enough for timestamp+null
|
||||
int nWritten;
|
||||
|
||||
GetLocalTime(&now);
|
||||
|
||||
if (now.wYear) {
|
||||
|
||||
// Mimic .NET 's' sortable time pattern
|
||||
nWritten = sprintf_s(szBuffer, _countof(szBuffer),
|
||||
"%u-%02u-%02uT%02u:%02u:%02u",
|
||||
now.wYear,
|
||||
now.wMonth,
|
||||
now.wDay,
|
||||
now.wHour,
|
||||
now.wMinute,
|
||||
now.wSecond);
|
||||
assert(nWritten && nWritten < _countof(szBuffer));
|
||||
|
||||
// no newline
|
||||
printf("%s: " ,szBuffer);
|
||||
}
|
||||
|
||||
va_list argList;
|
||||
va_start(argList, format);
|
||||
vprintf(format, argList);
|
||||
|
@ -528,67 +560,80 @@ bool IORequestGenerator::_LoadDLLs()
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool IORequestGenerator::_GetSystemPerfInfo(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pInfo, UINT32 uCpuCount) const
|
||||
bool IORequestGenerator::_GetSystemPerfInfo(vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION>& vSPPI, bool fVerbose) const
|
||||
{
|
||||
NTSTATUS Status = NO_ERROR;
|
||||
UINT32 uCpuCtr;
|
||||
WORD wActiveGroupCtr;
|
||||
BYTE bActiveProc;
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
NTSTATUS Status;
|
||||
ULONG CpuBase;
|
||||
WORD Group;
|
||||
WORD GroupCount;
|
||||
GROUP_AFFINITY GroupAffinity;
|
||||
PROCESSOR_NUMBER procNumber;
|
||||
bool fOk = true;
|
||||
|
||||
assert(NULL != pInfo);
|
||||
assert(uCpuCount > 0);
|
||||
|
||||
for (uCpuCtr=0,wActiveGroupCtr=0; wActiveGroupCtr < g_SystemInformation.processorTopology._vProcessorGroupInformation.size(); wActiveGroupCtr++)
|
||||
for (CpuBase = 0, Group = 0, GroupCount = (WORD) g_SystemInformation.processorTopology._vProcessorGroupInformation.size();
|
||||
Group < GroupCount;
|
||||
Group++)
|
||||
{
|
||||
ProcessorGroupInformation *pGroup = &g_SystemInformation.processorTopology._vProcessorGroupInformation[wActiveGroupCtr];
|
||||
|
||||
if (pGroup->_activeProcessorCount != 0) {
|
||||
ProcessorGroupInformation *pGroup = &g_SystemInformation.processorTopology._vProcessorGroupInformation[Group];
|
||||
|
||||
//
|
||||
// Affinitize to the group we're querying counters from
|
||||
// Note that an inactive group is not queried (its not clear this is a practical case).
|
||||
// Correct operation assumes the input SPPI array is prezeroed, which DISKSPD does do via
|
||||
// default vector(size_t) construction.
|
||||
//
|
||||
|
||||
GetCurrentProcessorNumberEx(&procNumber);
|
||||
if (pGroup->_activeProcessorCount != 0)
|
||||
{
|
||||
//
|
||||
// In multigroup environments, affinitize to the group we're querying counters from.
|
||||
//
|
||||
|
||||
if (procNumber.Group != wActiveGroupCtr)
|
||||
if (GroupCount > 1)
|
||||
{
|
||||
for (bActiveProc = 0; bActiveProc < pGroup->_maximumProcessorCount; bActiveProc++)
|
||||
SetGroupMask(Group, pGroup->_activeProcessorMask, &GroupAffinity);
|
||||
if (!SetThreadGroupAffinity(GetCurrentThread(), &GroupAffinity, nullptr))
|
||||
{
|
||||
if (pGroup->IsProcessorActive(bActiveProc))
|
||||
{
|
||||
SetProcGroupMask(wActiveGroupCtr, bActiveProc, &GroupAffinity);
|
||||
break;
|
||||
PrintError("get system perf info: failed to set affinity to Group %u\n", GroupAffinity.Group);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bActiveProc == pGroup->_maximumProcessorCount ||
|
||||
SetThreadGroupAffinity(hThread, &GroupAffinity, nullptr) == FALSE)
|
||||
//
|
||||
// The SPPI vector should (is) always be sized to span CPUs for all groups, make this explicit.
|
||||
//
|
||||
|
||||
if (CpuBase + pGroup->_activeProcessorCount > vSPPI.size())
|
||||
{
|
||||
fOk = false;
|
||||
break;
|
||||
}
|
||||
PrintError("get system perf info: unable to return (base CPU %u + group active CPU %u > size %u)\n",
|
||||
CpuBase,
|
||||
pGroup->_activeProcessorCount,
|
||||
vSPPI.size());
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
Status = g_pfnNtQuerySysInfo(SystemProcessorPerformanceInformation,
|
||||
(PVOID)(pInfo + uCpuCtr),
|
||||
(sizeof(*pInfo) * uCpuCount) - (uCpuCtr * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)),
|
||||
NULL);
|
||||
&vSPPI[CpuBase],
|
||||
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * pGroup->_activeProcessorCount,
|
||||
nullptr);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
fOk = false;
|
||||
break;
|
||||
}
|
||||
PrintError("get system perf info: status 0x%x querying for Group %u (%u CPUs)\n",
|
||||
Status,
|
||||
Group,
|
||||
pGroup->_activeProcessorCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
uCpuCtr += pGroup->_maximumProcessorCount;
|
||||
PrintVerbose(fVerbose,
|
||||
"get system perf info: queried for Group %u (%u CPUs)\n",
|
||||
Group,
|
||||
pGroup->_activeProcessorCount);
|
||||
}
|
||||
|
||||
return fOk;
|
||||
CpuBase += pGroup->_activeProcessorCount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferred, LPOVERLAPPED pOverlapped);
|
||||
|
@ -597,7 +642,7 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy
|
|||
{
|
||||
OVERLAPPED *pOverlapped = pIORequest->GetOverlapped();
|
||||
Target *pTarget = pIORequest->GetCurrentTarget();
|
||||
size_t iTarget = pTarget - &p->vTargets[0];
|
||||
size_t iTarget = pIORequest->GetCurrentTargetIndex();
|
||||
UINT32 iRequest = pIORequest->GetRequestIndex();
|
||||
LARGE_INTEGER li;
|
||||
BOOL rslt = true;
|
||||
|
@ -639,7 +684,7 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy
|
|||
li.QuadPart);
|
||||
#endif
|
||||
|
||||
if (p->pTimeSpan->GetMeasureLatency())
|
||||
if (p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev())
|
||||
{
|
||||
pIORequest->SetStartTime(PerfTimer::GetTime());
|
||||
}
|
||||
|
@ -718,10 +763,20 @@ static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBy
|
|||
return (rslt) ? true : false;
|
||||
}
|
||||
|
||||
static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred)
|
||||
|
||||
void completeIOat(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred, UINT64 ullCompletionTime)
|
||||
{
|
||||
Target *pTarget = pIORequest->GetCurrentTarget();
|
||||
size_t iTarget = pTarget - &p->vTargets[0];
|
||||
if (*p->pfAccountingOn)
|
||||
{
|
||||
p->pResults->vTargetResults[pIORequest->GetCurrentTargetIndex()].Add(
|
||||
dwBytesTransferred,
|
||||
pIORequest->GetIoType(),
|
||||
pIORequest->GetStartTime(),
|
||||
ullCompletionTime,
|
||||
*(p->pullStartTime),
|
||||
p->pTimeSpan->GetMeasureLatency(),
|
||||
p->pTimeSpan->GetCalculateIopsStdDev());
|
||||
}
|
||||
|
||||
if (TraceLoggingProviderEnabled(g_hEtwProvider,
|
||||
TRACE_LEVEL_VERBOSE,
|
||||
|
@ -738,6 +793,8 @@ static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytes
|
|||
TraceLoggingLevel(TRACE_LEVEL_VERBOSE));
|
||||
}
|
||||
|
||||
Target *pTarget = pIORequest->GetCurrentTarget();
|
||||
|
||||
//check if I/O transferred all of the requested bytes
|
||||
if (dwBytesTransferred != pTarget->GetBlockSizeInBytes())
|
||||
{
|
||||
|
@ -747,16 +804,6 @@ static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytes
|
|||
pTarget->GetBlockSizeInBytes());
|
||||
}
|
||||
|
||||
if (*p->pfAccountingOn)
|
||||
{
|
||||
p->pResults->vTargetResults[iTarget].Add(dwBytesTransferred,
|
||||
pIORequest->GetIoType(),
|
||||
pIORequest->GetStartTime(),
|
||||
*(p->pullStartTime),
|
||||
p->pTimeSpan->GetMeasureLatency(),
|
||||
p->pTimeSpan->GetCalculateIopsStdDev());
|
||||
}
|
||||
|
||||
// check if we should print a progress dot
|
||||
if (p->pProfile->GetProgress() != 0)
|
||||
{
|
||||
|
@ -768,20 +815,33 @@ static void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytes
|
|||
}
|
||||
}
|
||||
|
||||
void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred)
|
||||
{
|
||||
if (p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev())
|
||||
{
|
||||
completeIOat(p, pIORequest, dwBytesTransferred, PerfTimer::GetTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
completeIOat(p, pIORequest, dwBytesTransferred, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
// function called from worker thread
|
||||
// performs synch I/O
|
||||
//
|
||||
static bool doWorkUsingSynchronousIO(ThreadParameters *p)
|
||||
{
|
||||
bool fOk = true;
|
||||
BOOL fOk = true;
|
||||
BOOL rslt = FALSE;
|
||||
DWORD dwBytesTransferred;
|
||||
size_t cIORequests = p->vIORequest.size();
|
||||
|
||||
while(g_bRun && !g_bThreadError)
|
||||
{
|
||||
DWORD dwMinSleepTime = ~((DWORD)0);
|
||||
DWORD nIssued = 0;
|
||||
DWORD dwMinSleepTime = INFINITE;
|
||||
for (size_t i = 0; i < cIORequests; i++)
|
||||
{
|
||||
IORequest *pIORequest = &p->vIORequest[i];
|
||||
|
@ -800,6 +860,7 @@ static bool doWorkUsingSynchronousIO(ThreadParameters *p)
|
|||
}
|
||||
}
|
||||
|
||||
nIssued += 1;
|
||||
rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false);
|
||||
|
||||
if (!rslt)
|
||||
|
@ -813,8 +874,9 @@ static bool doWorkUsingSynchronousIO(ThreadParameters *p)
|
|||
}
|
||||
|
||||
// if no IOs were issued, wait for the next scheduling time
|
||||
if (dwMinSleepTime != ~((DWORD)0) && dwMinSleepTime != 0)
|
||||
if (!nIssued && dwMinSleepTime != INFINITE && dwMinSleepTime != 0)
|
||||
{
|
||||
p->pResults->WaitStats.ThrottleSleep += 1;
|
||||
Sleep(dwMinSleepTime);
|
||||
}
|
||||
|
||||
|
@ -834,15 +896,13 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion
|
|||
assert(nullptr != p);
|
||||
assert(nullptr != hCompletionPort);
|
||||
|
||||
bool fOk = true;
|
||||
BOOL fOk = true;
|
||||
BOOL rslt = FALSE;
|
||||
OVERLAPPED * pCompletedOvrp;
|
||||
ULONG_PTR ulCompletionKey;
|
||||
DWORD dwBytesTransferred;
|
||||
OverlappedQueue overlappedQueue;
|
||||
size_t cIORequests = p->vIORequest.size();
|
||||
BOOL fLatencyStats = p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev();
|
||||
|
||||
//start IO operations
|
||||
for (size_t i = 0; i < cIORequests; i++)
|
||||
{
|
||||
overlappedQueue.Add(p->vIORequest[i].GetOverlapped());
|
||||
|
@ -851,29 +911,47 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion
|
|||
//
|
||||
// perform work
|
||||
//
|
||||
DWORD dwMinSleepTime = INFINITE;
|
||||
DWORD dwWaitTime;
|
||||
|
||||
OVERLAPPED_ENTRY ovlEntry[16];
|
||||
const ULONG cOvlEntryMax = _countof(ovlEntry) < (ULONG)cIORequests ? _countof(ovlEntry) : (ULONG)cIORequests;
|
||||
ULONG cCompleted;
|
||||
size_t cUntilThrottle = cIORequests;
|
||||
|
||||
while(g_bRun && !g_bThreadError)
|
||||
{
|
||||
DWORD dwMinSleepTime = ~((DWORD)0);
|
||||
for (size_t i = 0; i < overlappedQueue.GetCount(); i++)
|
||||
{
|
||||
OVERLAPPED *pReadyOverlapped = overlappedQueue.Remove();
|
||||
IORequest *pIORequest = IORequest::OverlappedToIORequest(pReadyOverlapped);
|
||||
Target *pTarget = pIORequest->GetNextTarget();
|
||||
(void) pIORequest->GetNextTarget();
|
||||
|
||||
// check throttles
|
||||
if (p->vThroughputMeters.size() != 0)
|
||||
{
|
||||
size_t iTarget = pTarget - &p->vTargets[0];
|
||||
ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[iTarget];
|
||||
ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[pIORequest->GetCurrentTargetIndex()];
|
||||
|
||||
cUntilThrottle -= 1;
|
||||
|
||||
DWORD dwSleepTime = pThroughputMeter->GetSleepTime();
|
||||
if (pThroughputMeter->IsRunning() && dwSleepTime > 0)
|
||||
{
|
||||
dwMinSleepTime = min(dwMinSleepTime, dwSleepTime);
|
||||
overlappedQueue.Add(pReadyOverlapped);
|
||||
|
||||
// continue if throttle not hit
|
||||
if (cUntilThrottle)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// at throttle, no IO to dispatch
|
||||
pIORequest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch IO - skipped iff at throttle
|
||||
if (pIORequest)
|
||||
{
|
||||
rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false);
|
||||
|
||||
if (!rslt && GetLastError() != ERROR_IO_PENDING)
|
||||
|
@ -884,26 +962,83 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rslt && pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On)
|
||||
if (rslt && pIORequest->GetCurrentTarget()->GetMemoryMappedIoMode() == MemoryMappedIoMode::On)
|
||||
{
|
||||
completeIO(p, pIORequest, dwBytesTransferred);
|
||||
overlappedQueue.Add(pReadyOverlapped);
|
||||
|
||||
// a completed memory mapped IO resets the throttle so that we traverse
|
||||
// back to it in fair-order before considering throttle again.
|
||||
// note this will drop through to lookside for completions, not wait
|
||||
dwMinSleepTime = INFINITE;
|
||||
cUntilThrottle = overlappedQueue.GetCount();
|
||||
}
|
||||
}
|
||||
|
||||
// if no IOs are in flight, wait for the next scheduling time
|
||||
if ((overlappedQueue.GetCount() == p->vIORequest.size()) && dwMinSleepTime != ~((DWORD)0))
|
||||
// look for IO completion
|
||||
// queue is fully dispatched: set wait, reset throttle wait
|
||||
if (!overlappedQueue.GetCount())
|
||||
{
|
||||
Sleep(dwMinSleepTime);
|
||||
assert(!cUntilThrottle);
|
||||
dwWaitTime = dwMinSleepTime = INFINITE;
|
||||
p->pResults->WaitStats.Wait += 1;
|
||||
}
|
||||
|
||||
// wait till one of the IO operations finishes
|
||||
if (GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred, &ulCompletionKey, &pCompletedOvrp, 1) != 0)
|
||||
// queue is not fully dispatched ...
|
||||
// if at the throttle, wait throttle time and reset
|
||||
else if (!cUntilThrottle)
|
||||
{
|
||||
//find which I/O operation it was (so we know to which buffer should we use)
|
||||
IORequest *pIORequest = IORequest::OverlappedToIORequest(pCompletedOvrp);
|
||||
completeIO(p, pIORequest, dwBytesTransferred);
|
||||
overlappedQueue.Add(pCompletedOvrp);
|
||||
dwWaitTime = dwMinSleepTime;
|
||||
dwMinSleepTime = INFINITE;
|
||||
cUntilThrottle = overlappedQueue.GetCount();
|
||||
|
||||
if (cIORequests == cUntilThrottle)
|
||||
{
|
||||
// all throttled, none dispatched - just sleep
|
||||
p->pResults->WaitStats.ThrottleSleep += 1;
|
||||
Sleep(dwWaitTime);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// throttled, but some dispatched - wait for completions
|
||||
p->pResults->WaitStats.ThrottleWait += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// queue is not fully dispatched ...
|
||||
// if this run is not for latency stats, optimize for dispatch and
|
||||
// skip completion lookasides
|
||||
else if (!fLatencyStats)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// else lookaside
|
||||
else
|
||||
{
|
||||
dwWaitTime = 0;
|
||||
p->pResults->WaitStats.Lookaside += 1;
|
||||
}
|
||||
|
||||
if (GetQueuedCompletionStatusEx(hCompletionPort, ovlEntry, cOvlEntryMax, &cCompleted, dwWaitTime, FALSE) != 0)
|
||||
{
|
||||
UINT64 ullCompletionTime = 0;
|
||||
|
||||
if (fLatencyStats)
|
||||
{
|
||||
// single completion time estimate for all completions
|
||||
ullCompletionTime = PerfTimer::GetTime();
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < cCompleted; i++)
|
||||
{
|
||||
completeIOat(p, IORequest::OverlappedToIORequest(ovlEntry[i].lpOverlapped), ovlEntry[i].dwNumberOfBytesTransferred, ullCompletionTime);
|
||||
overlappedQueue.Add(ovlEntry[i].lpOverlapped);
|
||||
}
|
||||
|
||||
// must reevaluate queue in fair order before next throttle
|
||||
cUntilThrottle = overlappedQueue.GetCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -915,6 +1050,12 @@ static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletion
|
|||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// stats for lookaside waits
|
||||
if (dwWaitTime == 0)
|
||||
{
|
||||
p->pResults->WaitStats.LookasideCompletion[cCompleted < _countof(p->pResults->WaitStats.LookasideCompletion) ? cCompleted : _countof(p->pResults->WaitStats.LookasideCompletion) - 1] += 1;
|
||||
}
|
||||
} // end work loop
|
||||
|
||||
cleanup:
|
||||
|
@ -930,7 +1071,6 @@ VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferre
|
|||
assert(NULL != pOverlapped);
|
||||
|
||||
BOOL rslt = FALSE;
|
||||
|
||||
ThreadParameters *p = (ThreadParameters *)pOverlapped->hEvent;
|
||||
|
||||
assert(NULL != p);
|
||||
|
@ -949,14 +1089,12 @@ VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferre
|
|||
// start a new IO operation
|
||||
if (g_bRun && !g_bThreadError)
|
||||
{
|
||||
Target *pTarget = pIORequest->GetNextTarget();
|
||||
size_t iTarget = pTarget - &p->vTargets[0];
|
||||
|
||||
(void) pIORequest->GetNextTarget();
|
||||
rslt = issueNextIO(p, pIORequest, NULL, true);
|
||||
|
||||
if (!rslt)
|
||||
{
|
||||
PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, iTarget, (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError());
|
||||
PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, pIORequest->GetCurrentTargetIndex(), (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -976,18 +1114,18 @@ static bool doWorkUsingCompletionRoutines(ThreadParameters *p)
|
|||
BOOL rslt = FALSE;
|
||||
|
||||
// start IO operations
|
||||
// completion routines will reissue 1:1
|
||||
UINT32 cIORequests = (UINT32)p->vIORequest.size();
|
||||
|
||||
for (size_t iIORequest = 0; iIORequest < cIORequests; iIORequest++) {
|
||||
IORequest *pIORequest = &p->vIORequest[iIORequest];
|
||||
Target *pTarget = pIORequest->GetNextTarget();
|
||||
size_t iTarget = pTarget - &p->vTargets[0];
|
||||
for (size_t i = 0; i < cIORequests; i++)
|
||||
{
|
||||
IORequest *pIORequest = &p->vIORequest[i];
|
||||
|
||||
rslt = issueNextIO(p, pIORequest, NULL, true);
|
||||
|
||||
if (!rslt)
|
||||
{
|
||||
PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, iTarget, (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError());
|
||||
PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, pIORequest->GetCurrentTargetIndex(), (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError());
|
||||
fOk = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -1090,7 +1228,7 @@ DWORD WINAPI threadFunc(LPVOID cookie)
|
|||
{
|
||||
GROUP_AFFINITY GroupAffinity;
|
||||
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "affinitizing thread %u to Group %u / CPU %u\n", p->ulThreadNo, p->wGroupNum, p->bProcNum);
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u: affinitizing to Group %u / CPU %u\n", p->ulThreadNo, p->wGroupNum, p->bProcNum);
|
||||
SetProcGroupMask(p->wGroupNum, p->bProcNum, &GroupAffinity);
|
||||
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
|
@ -1327,21 +1465,25 @@ DWORD WINAPI threadFunc(LPVOID cookie)
|
|||
fOk = false;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u starting: file '%s' relative thread %u",
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u: file '%s' relative thread %u (random seed: %u)\n",
|
||||
p->ulThreadNo,
|
||||
pTarget->GetPath().c_str(),
|
||||
p->ulRelativeThreadNo);
|
||||
p->ulRelativeThreadNo,
|
||||
p->ulRandSeed);
|
||||
|
||||
if (pTarget->GetRandomRatio() > 0)
|
||||
{
|
||||
PrintVerbose(p->pProfile->GetVerbose(), ", %u% random pattern\n",
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u: %u%% random IO\n",
|
||||
p->ulThreadNo,
|
||||
pTarget->GetRandomRatio());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintVerbose(p->pProfile->GetVerbose(), ", %ssequential file offset\n", pTarget->GetUseInterlockedSequential() ? "interlocked ":"");
|
||||
}
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u: %ssequential IO\n",
|
||||
p->ulThreadNo,
|
||||
pTarget->GetUseInterlockedSequential() ? "interlocked ":"");
|
||||
}
|
||||
|
||||
// allocate memory for a data buffer
|
||||
|
@ -1402,8 +1544,6 @@ DWORD WINAPI threadFunc(LPVOID cookie)
|
|||
// TODO: copy parameters for better memory locality?
|
||||
// TODO: tell the main thread we're ready
|
||||
|
||||
PrintVerbose(p->pProfile->GetVerbose(), "thread %u started (random seed: %u)\n", p->ulThreadNo, p->ulRandSeed);
|
||||
|
||||
p->pResults->vTargetResults.clear();
|
||||
p->pResults->vTargetResults.resize(p->vTargets.size());
|
||||
|
||||
|
@ -2093,14 +2233,13 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
//
|
||||
// allocate memory for performance counters
|
||||
//
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfInit(g_SystemInformation.processorTopology._ulProcCount);
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfDone(g_SystemInformation.processorTopology._ulProcCount);
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfDiff(g_SystemInformation.processorTopology._ulProcCount);
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfInit(g_SystemInformation.processorTopology._ulProcessorCount);
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfDone(g_SystemInformation.processorTopology._ulProcessorCount);
|
||||
vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> vPerfDiff(g_SystemInformation.processorTopology._ulProcessorCount);
|
||||
|
||||
//
|
||||
// create start event
|
||||
//
|
||||
|
||||
hStartEvent = CreateEvent(NULL, TRUE, FALSE, "");
|
||||
if (NULL == hStartEvent)
|
||||
{
|
||||
|
@ -2252,7 +2391,7 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
|
||||
//Set thread group and proc affinity
|
||||
|
||||
// Default: Round robin cores in order of groups, starting at group 0.
|
||||
// Default: Round robin cpus in order of groups, starting at group 0.
|
||||
// Fill each group before moving to next.
|
||||
if (vAffinity.size() == 0)
|
||||
{
|
||||
|
@ -2313,7 +2452,6 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
BOOL bBreak = FALSE;
|
||||
PEVENT_TRACE_PROPERTIES pETWSession = NULL;
|
||||
|
||||
PrintVerbose(profile.GetVerbose(), "starting warm up...\n");
|
||||
//
|
||||
// send start signal
|
||||
//
|
||||
|
@ -2332,6 +2470,7 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
{
|
||||
TraceLoggingActivity<g_hEtwProvider, DISKSPD_TRACE_INFO, TRACE_LEVEL_NONE> WarmActivity;
|
||||
TraceLoggingWriteStart(WarmActivity, "Warm Up");
|
||||
PrintVerbose(profile.GetVerbose(), "starting warm up for %us...\n", timeSpan.GetWarmup());
|
||||
|
||||
if (bSynchStop)
|
||||
{
|
||||
|
@ -2382,8 +2521,6 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
PrintVerbose(profile.GetVerbose(), "tracing events\n");
|
||||
}
|
||||
|
||||
PrintVerbose(profile.GetVerbose(), "starting measurements...\n");
|
||||
|
||||
//
|
||||
// notify the front-end that the test is about to start;
|
||||
// do it before starting timing in order not to perturb measurements
|
||||
|
@ -2396,7 +2533,7 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
//
|
||||
// read performance counters
|
||||
//
|
||||
if (_GetSystemPerfInfo(&vPerfInit[0], g_SystemInformation.processorTopology._ulProcCount) == FALSE)
|
||||
if (_GetSystemPerfInfo(vPerfInit, profile.GetVerbose()) == FALSE)
|
||||
{
|
||||
PrintError("Error reading performance counters\n");
|
||||
_StopETW(fUseETW, hTraceSession);
|
||||
|
@ -2407,13 +2544,11 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
TraceLoggingActivity<g_hEtwProvider, DISKSPD_TRACE_INFO, TRACE_LEVEL_NONE> RunActivity;
|
||||
TraceLoggingWriteStart(RunActivity, "Run Time");
|
||||
|
||||
PrintVerbose(profile.GetVerbose(), "starting measurements for %us...\n", timeSpan.GetDuration());
|
||||
|
||||
//get cycle count (it will be used to calculate actual work time)
|
||||
ullStartTime = PerfTimer::GetTime();
|
||||
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 28931 )
|
||||
fAccountingOn = true;
|
||||
#pragma warning( pop )
|
||||
|
||||
assert(timeSpan.GetDuration() > 0);
|
||||
if (bSynchStop)
|
||||
|
@ -2434,14 +2569,14 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
Sleep(1000 * timeSpan.GetDuration());
|
||||
}
|
||||
|
||||
fAccountingOn = false;
|
||||
|
||||
//get cycle count and perf counters
|
||||
fAccountingOn = false;
|
||||
ullTimeDiff = PerfTimer::GetTime() - ullStartTime;
|
||||
PrintVerbose(profile.GetVerbose(), "stopped measurements, total measured time %.2lfs...\n", PerfTimer::PerfTimeToSeconds(ullTimeDiff));
|
||||
|
||||
TraceLoggingWriteStop(RunActivity, "Run Time");
|
||||
|
||||
if (_GetSystemPerfInfo(&vPerfDone[0], g_SystemInformation.processorTopology._ulProcCount) == FALSE)
|
||||
if (_GetSystemPerfInfo(vPerfDone, profile.GetVerbose()) == FALSE)
|
||||
{
|
||||
PrintError("Error getting performance counters\n");
|
||||
_StopETW(fUseETW, hTraceSession);
|
||||
|
@ -2477,11 +2612,11 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
ullTimeDiff = 0; // mark that no test was run
|
||||
}
|
||||
|
||||
PrintVerbose(profile.GetVerbose(), "starting cool down...\n");
|
||||
if ((timeSpan.GetCooldown() > 0) && !bBreak)
|
||||
{
|
||||
TraceLoggingActivity<g_hEtwProvider, DISKSPD_TRACE_INFO, TRACE_LEVEL_NONE> CoolActivity;
|
||||
TraceLoggingWriteStart(CoolActivity, "Cool Down");
|
||||
PrintVerbose(profile.GetVerbose(), "starting cool down for %us...\n", timeSpan.GetCooldown());
|
||||
|
||||
if (bSynchStop)
|
||||
{
|
||||
|
@ -2553,21 +2688,51 @@ bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, co
|
|||
//
|
||||
// compute time spent by each cpu
|
||||
//
|
||||
for (unsigned int p = 0; p < g_SystemInformation.processorTopology._ulProcCount; ++p)
|
||||
for (DWORD p = 0; p < g_SystemInformation.processorTopology._ulProcessorCount; ++p)
|
||||
{
|
||||
assert(vPerfDone[p].IdleTime.QuadPart >= vPerfInit[p].IdleTime.QuadPart);
|
||||
assert(vPerfDone[p].KernelTime.QuadPart >= vPerfInit[p].KernelTime.QuadPart);
|
||||
assert(vPerfDone[p].UserTime.QuadPart >= vPerfInit[p].UserTime.QuadPart);
|
||||
assert(vPerfDone[p].Reserved1[0].QuadPart >= vPerfInit[p].Reserved1[0].QuadPart);
|
||||
assert(vPerfDone[p].Reserved1[1].QuadPart >= vPerfInit[p].Reserved1[1].QuadPart);
|
||||
assert(vPerfDone[p].Reserved2 >= vPerfInit[p].Reserved2);
|
||||
|
||||
vPerfDiff[p].IdleTime.QuadPart = vPerfDone[p].IdleTime.QuadPart - vPerfInit[p].IdleTime.QuadPart;
|
||||
vPerfDiff[p].KernelTime.QuadPart = vPerfDone[p].KernelTime.QuadPart - vPerfInit[p].KernelTime.QuadPart;
|
||||
vPerfDiff[p].UserTime.QuadPart = vPerfDone[p].UserTime.QuadPart - vPerfInit[p].UserTime.QuadPart;
|
||||
vPerfDiff[p].Reserved1[0].QuadPart = vPerfDone[p].Reserved1[0].QuadPart - vPerfInit[p].Reserved1[0].QuadPart;
|
||||
vPerfDiff[p].Reserved1[1].QuadPart = vPerfDone[p].Reserved1[1].QuadPart - vPerfInit[p].Reserved1[1].QuadPart;
|
||||
vPerfDiff[p].Reserved2 = vPerfDone[p].Reserved2 - vPerfInit[p].Reserved2;
|
||||
|
||||
//
|
||||
// Handle clock measurement jitter; if the difference is negative, set it to 0. This is usually seen
|
||||
// as a -10000000 (full second of 100ns units) difference over very short runs.
|
||||
//
|
||||
// If the sum of kernel and user time is 0, treat it as a full idle with placeholder values. This provides
|
||||
// a nonzero denominator for the CPU utilization calculation and avoids divide by zero -> INF results.
|
||||
// Note that system clock convention is that kernel time includes idle time.
|
||||
//
|
||||
|
||||
if (vPerfDiff[p].IdleTime.QuadPart < 0)
|
||||
{
|
||||
PrintVerbose(profile.GetVerbose(), "time fixup: IdleTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].IdleTime.QuadPart, vPerfInit[p].IdleTime.QuadPart);
|
||||
vPerfDiff[p].IdleTime.QuadPart = 0;
|
||||
}
|
||||
|
||||
if (vPerfDiff[p].KernelTime.QuadPart < 0)
|
||||
{
|
||||
PrintVerbose(profile.GetVerbose(), "time fixup: KernelTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].KernelTime.QuadPart, vPerfInit[p].KernelTime.QuadPart);
|
||||
vPerfDiff[p].KernelTime.QuadPart = 0;
|
||||
}
|
||||
|
||||
if (vPerfDiff[p].UserTime.QuadPart < 0)
|
||||
{
|
||||
PrintVerbose(profile.GetVerbose(), "time fixup: UserTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].UserTime.QuadPart, vPerfInit[p].UserTime.QuadPart);
|
||||
vPerfDiff[p].UserTime.QuadPart = 0;
|
||||
}
|
||||
|
||||
if (vPerfDiff[p].KernelTime.QuadPart + vPerfDiff[p].UserTime.QuadPart == 0)
|
||||
{
|
||||
PrintVerbose(profile.GetVerbose(), "time fixup: KernelTime+UserTime = 0 @ %u : ticks K (%lld - %lld) + U (%lld - %lld)\n", p,
|
||||
vPerfDone[p].KernelTime.QuadPart, vPerfInit[p].KernelTime.QuadPart,
|
||||
vPerfDone[p].UserTime.QuadPart, vPerfInit[p].UserTime.QuadPart);
|
||||
|
||||
vPerfDiff[p].IdleTime.QuadPart = vPerfDiff[p].KernelTime.QuadPart = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -27,6 +27,7 @@ SOFTWARE.
|
|||
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ThroughputMeter.h"
|
||||
|
||||
ThroughputMeter::ThroughputMeter(void) :
|
||||
|
@ -99,10 +100,33 @@ DWORD ThroughputMeter::GetSleepTime(void) const
|
|||
}
|
||||
|
||||
DWORD ThroughputMeter::_GetThrottleTime(void) const
|
||||
{
|
||||
if ((g_ExperimentFlags & EXPERIMENT_TPUT_CALC) == 0)
|
||||
{
|
||||
ULONGLONG cbExpected = (GetTickCount64() - _ullStartTimestamp) * _cBytesPerMillisecond;
|
||||
return cbExpected >= (_cbCompleted + _cbBlockSize) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// prototype to calculate an actual sleep time
|
||||
// under higher loads the ideal delay is likely in the microsecond range, but the minimum sleep is 1 ms
|
||||
// however, at low rates it may be reasonable to calculate the delay and use it if > 1ms
|
||||
|
||||
ULONGLONG elapsed = GetTickCount64() - _ullStartTimestamp;
|
||||
ULONGLONG bytesNext = _cbCompleted + _cbBlockSize;
|
||||
|
||||
if (elapsed * _cBytesPerMillisecond > bytesNext)
|
||||
{
|
||||
// below rate - no sleep
|
||||
return 0;
|
||||
}
|
||||
|
||||
// above rate - sleep at least 1 ms
|
||||
ULONGLONG sleepTarget = (bytesNext / _cBytesPerMillisecond) - elapsed;
|
||||
|
||||
return max((DWORD)sleepTarget, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ThroughputMeter::Adjust(size_t cb)
|
||||
{
|
||||
|
|
21
README.md
21
README.md
|
@ -17,6 +17,27 @@ What's New?
|
|||
|
||||
## DISKSPD
|
||||
|
||||
# DISKSPD 2.2 6/3/2024
|
||||
|
||||
**NOTE:** changes to the asynchronous IO loop will require rebaselining results with queue depths greater than 1.
|
||||
The new design drains the completion queue more aggressively, shrinking delays that impacted latency measurement
|
||||
especially on faster storage targeting higher queue depths. Latency measurement is improved at a very small cost
|
||||
to rates, as well as improving rates when latency measurement is not used (`-D` or `-L`) due to batch dequeue.
|
||||
|
||||
Smaller IO sizes will see the most change.
|
||||
|
||||
* New: Socket, NUMA, Core and Power Efficiency Class (big/little cores) added to processor topology reporting (XML and text output)
|
||||
* topology elements only displayed in text results when > 1 are present (e.g. multi-socket systems)
|
||||
* CPU numbering remains group relative, as is the new Core numbering
|
||||
* highest Power Efficiency Class is marked with a `P` suffix (this will usually be `1P` v. `0`)
|
||||
* **NOTE**: efficiency classes can have major impact; work on heterogenous systems **must** be aware of core properties in combination thread affinity rules (see `-a` and `-n `)
|
||||
* New: active power scheme reporting
|
||||
* New: base target offset switch now allows range specification: `-Bbase[:length]`; replaces `-B` and `-f`
|
||||
* post-run latency histogram processing now significantly faster
|
||||
* verbose output is more consistent; includes actual warmup, measured and cooldown intervals v. expected
|
||||
|
||||
Binary release supports down to Windows 8 and Windows Server 2012; now uses the Universal CRT.
|
||||
|
||||
# DISKSPD 2.1 7/1/2021
|
||||
|
||||
* New `-g<n>i` form allowing throughput limit specification in units of IOPS (per specified blocksize)
|
||||
|
|
|
@ -730,6 +730,11 @@ void ResultParser::_PrintProfile(const Profile& profile)
|
|||
{
|
||||
_Print("\nCommand Line: %s\n", profile.GetCmdLine().c_str());
|
||||
_Print("\n");
|
||||
if (g_ExperimentFlags)
|
||||
{
|
||||
_Print("Experiment Flags: 0x%x (%u)\n", g_ExperimentFlags, g_ExperimentFlags);
|
||||
_Print("\n");
|
||||
}
|
||||
_Print("Input parameters:\n\n");
|
||||
if (profile.GetVerbose())
|
||||
{
|
||||
|
@ -754,98 +759,114 @@ void ResultParser::_PrintSystemInfo(const SystemInformation& system)
|
|||
|
||||
void ResultParser::_PrintCpuUtilization(const Results& results, const SystemInformation& system)
|
||||
{
|
||||
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
|
||||
size_t ulBaseProc = 0;
|
||||
size_t ulActiveProcCount = 0;
|
||||
size_t ulNumGroups = system.processorTopology._vProcessorGroupInformation.size();
|
||||
const auto& topo = system.processorTopology;
|
||||
size_t procCount = results.vSystemProcessorPerfInfo.size();
|
||||
size_t baseProc = 0;
|
||||
BYTE efficiencyClass = 0;
|
||||
BYTE processorCore = 0;
|
||||
|
||||
char szFloatBuffer[1024];
|
||||
bool fMultiSocket = topo._vProcessorSocketInformation.size() > 1;
|
||||
bool fMultiNode = topo._vProcessorNumaInformation.size() > 1;
|
||||
bool fMultiGroup = topo._vProcessorGroupInformation.size() > 1;
|
||||
|
||||
if (ulNumGroups == 1) {
|
||||
_Print("\nCPU | Usage | User | Kernel | Idle\n");
|
||||
}
|
||||
else {
|
||||
_Print("\nGroup | CPU | Usage | User | Kernel | Idle\n");
|
||||
}
|
||||
_Print("-------------------------------------------\n");
|
||||
//
|
||||
// Columns dynamically expand based on whether the system has multiple of the following,
|
||||
// in hierarchical order, followed by CPU #:
|
||||
//
|
||||
// Socket NUMA Group Core Class
|
||||
//
|
||||
// Note that core & cpu number are group-relative, not absolute (or NUMA or socket relative)
|
||||
//
|
||||
|
||||
_Print("\n");
|
||||
if (fMultiSocket) { _Print("Socket | "); }
|
||||
if (fMultiNode) { _Print("Node | "); }
|
||||
if (fMultiGroup) { _Print("Group | "); }
|
||||
if (topo._fSMT) { _Print("Core | "); }
|
||||
if (topo._ubPerformanceEfficiencyClass) { _Print("Class | "); }
|
||||
_Print("CPU | Usage | User | Kernel | Idle\n");
|
||||
if (fMultiSocket) { _Print("---------"); }
|
||||
if (fMultiNode) { _Print("-------"); }
|
||||
if (fMultiGroup) { _Print("--------"); }
|
||||
if (topo._fSMT) { _Print("-------"); }
|
||||
if (topo._ubPerformanceEfficiencyClass) { _Print("--------"); }
|
||||
_Print("----------------------------------------\n");
|
||||
|
||||
double busyTime = 0;
|
||||
double totalIdleTime = 0;
|
||||
double totalUserTime = 0;
|
||||
double totalKrnlTime = 0;
|
||||
|
||||
for (unsigned int ulGroup = 0; ulGroup < ulNumGroups; ulGroup++) {
|
||||
const ProcessorGroupInformation *pGroup = &system.processorTopology._vProcessorGroupInformation[ulGroup];
|
||||
for (const auto& group : topo._vProcessorGroupInformation) {
|
||||
|
||||
// System has multiple groups but we only have counters for the first one
|
||||
if (ulBaseProc >= ulProcCount) {
|
||||
break;
|
||||
// Sanity assert - results are sized to the sum of active processors
|
||||
assert(baseProc + group._activeProcessorCount <= procCount);
|
||||
|
||||
for (BYTE processor = 0; processor < group._activeProcessorCount; processor++) {
|
||||
|
||||
long long fTime = results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart +
|
||||
results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart;
|
||||
|
||||
double idleTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].IdleTime.QuadPart / fTime;
|
||||
double krnlTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart / fTime;
|
||||
double userTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart / fTime;
|
||||
double usedTime = (krnlTime - idleTime) + userTime;
|
||||
|
||||
if (fMultiSocket) {
|
||||
_Print("%7u| ", topo.GetSocketOfProcessor(group._groupNumber, processor));
|
||||
}
|
||||
if (fMultiNode) {
|
||||
_Print("%5u| ", topo.GetNumaOfProcessor(group._groupNumber, processor));
|
||||
}
|
||||
if (fMultiGroup) {
|
||||
_Print("%6u| ", group._groupNumber);
|
||||
}
|
||||
processorCore = topo.GetCoreOfProcessor(group._groupNumber, processor, efficiencyClass);
|
||||
if (topo._fSMT){
|
||||
_Print("%5u| ", processorCore);
|
||||
}
|
||||
if (topo._ubPerformanceEfficiencyClass) {
|
||||
_Print("%5u%c| ",
|
||||
efficiencyClass,
|
||||
efficiencyClass == topo._ubPerformanceEfficiencyClass ? 'P' : ' ');
|
||||
}
|
||||
|
||||
for (unsigned int ulProcessor = 0; ulProcessor < pGroup->_maximumProcessorCount; ulProcessor++) {
|
||||
double idleTime;
|
||||
double userTime;
|
||||
double krnlTime;
|
||||
double thisTime;
|
||||
|
||||
if (!pGroup->IsProcessorActive((BYTE)ulProcessor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long long fTime = results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].KernelTime.QuadPart +
|
||||
results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].UserTime.QuadPart;
|
||||
|
||||
idleTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].IdleTime.QuadPart / fTime;
|
||||
krnlTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].KernelTime.QuadPart / fTime;
|
||||
userTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].UserTime.QuadPart / fTime;
|
||||
|
||||
thisTime = (krnlTime + userTime) - idleTime;
|
||||
|
||||
if (ulNumGroups == 1) {
|
||||
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "%4u| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
|
||||
ulProcessor,
|
||||
thisTime,
|
||||
_Print("%4u| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
|
||||
processor,
|
||||
usedTime,
|
||||
userTime,
|
||||
krnlTime - idleTime,
|
||||
idleTime);
|
||||
}
|
||||
else {
|
||||
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "%6u| %4u| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
|
||||
ulGroup,
|
||||
ulProcessor,
|
||||
thisTime,
|
||||
userTime,
|
||||
krnlTime - idleTime,
|
||||
idleTime);
|
||||
}
|
||||
|
||||
_Print("%s", szFloatBuffer);
|
||||
|
||||
busyTime += thisTime;
|
||||
busyTime += usedTime;
|
||||
totalIdleTime += idleTime;
|
||||
totalUserTime += userTime;
|
||||
totalKrnlTime += krnlTime;
|
||||
ulActiveProcCount += 1;
|
||||
}
|
||||
|
||||
ulBaseProc += pGroup->_maximumProcessorCount;
|
||||
baseProc += group._activeProcessorCount;
|
||||
}
|
||||
|
||||
if (ulActiveProcCount == 0) {
|
||||
ulActiveProcCount = 1;
|
||||
}
|
||||
assert(baseProc == procCount);
|
||||
|
||||
_Print("-------------------------------------------\n");
|
||||
if (fMultiSocket) { _Print("---------"); }
|
||||
if (fMultiNode) { _Print("-------"); }
|
||||
if (fMultiGroup) { _Print("--------"); }
|
||||
if (topo._fSMT) { _Print("-------"); }
|
||||
if (topo._ubPerformanceEfficiencyClass) { _Print("--------"); }
|
||||
_Print("----------------------------------------\n");
|
||||
|
||||
sprintf_s(szFloatBuffer, sizeof(szFloatBuffer),
|
||||
ulNumGroups == 1 ?
|
||||
"avg.| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n" :
|
||||
" avg.| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
|
||||
busyTime / ulActiveProcCount,
|
||||
totalUserTime / ulActiveProcCount,
|
||||
(totalKrnlTime - totalIdleTime) / ulActiveProcCount,
|
||||
totalIdleTime / ulActiveProcCount);
|
||||
_Print("%s", szFloatBuffer);
|
||||
if (fMultiSocket) { _Print(" "); }
|
||||
if (fMultiNode) { _Print(" "); }
|
||||
if (fMultiGroup) { _Print(" "); }
|
||||
if (topo._fSMT) { _Print(" "); }
|
||||
if (topo._ubPerformanceEfficiencyClass) { _Print(" "); }
|
||||
|
||||
_Print("avg.| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n",
|
||||
busyTime / procCount,
|
||||
totalUserTime / procCount,
|
||||
(totalKrnlTime - totalIdleTime) / procCount,
|
||||
totalIdleTime / procCount);
|
||||
}
|
||||
|
||||
void ResultParser::_PrintSectionFieldNames(const TimeSpan& timeSpan)
|
||||
|
@ -935,8 +956,7 @@ void ResultParser::_PrintSection(_SectionEnum section, const TimeSpan& timeSpan,
|
|||
|
||||
if (timeSpan.GetMeasureLatency())
|
||||
{
|
||||
double avgLat = latencyHistogram.GetAvg()/1000;
|
||||
_Print(" | %8.3f", avgLat);
|
||||
_Print(" | %8.3f", latencyHistogram.GetAvg()/1000);
|
||||
}
|
||||
|
||||
if (timeSpan.GetCalculateIopsStdDev())
|
||||
|
@ -970,13 +990,6 @@ void ResultParser::_PrintSection(_SectionEnum section, const TimeSpan& timeSpan,
|
|||
|
||||
_PrintSectionBorderLine(timeSpan);
|
||||
|
||||
double totalAvgLat = 0;
|
||||
|
||||
if (timeSpan.GetMeasureLatency())
|
||||
{
|
||||
totalAvgLat = totalLatencyHistogram.GetAvg()/1000;
|
||||
}
|
||||
|
||||
_Print("total: %15llu | %12llu | %10.2f | %10.2f",
|
||||
ullTotalBytesCount,
|
||||
ullTotalIOCount,
|
||||
|
@ -985,7 +998,7 @@ void ResultParser::_PrintSection(_SectionEnum section, const TimeSpan& timeSpan,
|
|||
|
||||
if (timeSpan.GetMeasureLatency())
|
||||
{
|
||||
_Print(" | %8.3f", totalAvgLat);
|
||||
_Print(" | %8.3f", totalLatencyHistogram.GetAvg()/1000);
|
||||
}
|
||||
|
||||
if (timeSpan.GetCalculateIopsStdDev())
|
||||
|
@ -1037,7 +1050,7 @@ void ResultParser::_PrintLatencyPercentiles(const Results& results)
|
|||
for (auto i : perTargetTotalHistogram)
|
||||
{
|
||||
std::string path = i.first;
|
||||
_Print("\n%s\n", path.c_str());
|
||||
_Print("\nLatency distribution: %s\n", path.c_str());
|
||||
_PrintLatencyChart(perTargetReadHistogram[path],
|
||||
perTargetWriteHistogram[path],
|
||||
perTargetTotalHistogram[path]);
|
||||
|
@ -1062,7 +1075,7 @@ void ResultParser::_PrintLatencyPercentiles(const Results& results)
|
|||
}
|
||||
}
|
||||
|
||||
_Print("\ntotal:\n");
|
||||
_Print("\nTotal latency distribution:\n");
|
||||
_PrintLatencyChart(readLatencyHistogram, writeLatencyHistogram, totalLatencyHistogram);
|
||||
}
|
||||
|
||||
|
@ -1141,6 +1154,32 @@ string ResultParser::ParseProfile(const Profile& profile)
|
|||
return _sResult;
|
||||
}
|
||||
|
||||
void ResultParser::_PrintWaitStats(const Results &results)
|
||||
{
|
||||
_Print("Wait Statistics\n");
|
||||
_Print("thread | completion wait | throttle wait - sleep | lookaside | 0 - 7+ complete per lookaside\n");
|
||||
_Print("-----------------------------------------------------------------------------------------------\n");
|
||||
for (unsigned int iThread = 0; iThread < results.vThreadResults.size(); ++iThread)
|
||||
{
|
||||
const ThreadResults& threadResults = results.vThreadResults[iThread];
|
||||
_Print(
|
||||
"%6u | %15llu | %13llu - %6llu | %9llu | %llu %llu %llu %llu %llu %llu %llu %llu\n",
|
||||
iThread,
|
||||
threadResults.WaitStats.Wait,
|
||||
threadResults.WaitStats.ThrottleWait,
|
||||
threadResults.WaitStats.ThrottleSleep,
|
||||
threadResults.WaitStats.Lookaside,
|
||||
threadResults.WaitStats.LookasideCompletion[0],
|
||||
threadResults.WaitStats.LookasideCompletion[1],
|
||||
threadResults.WaitStats.LookasideCompletion[2],
|
||||
threadResults.WaitStats.LookasideCompletion[3],
|
||||
threadResults.WaitStats.LookasideCompletion[4],
|
||||
threadResults.WaitStats.LookasideCompletion[5],
|
||||
threadResults.WaitStats.LookasideCompletion[6],
|
||||
threadResults.WaitStats.LookasideCompletion[7]);
|
||||
}
|
||||
}
|
||||
|
||||
string ResultParser::ParseResults(const Profile& profile, const SystemInformation& system, vector<Results> vResults)
|
||||
{
|
||||
_sResult.clear();
|
||||
|
@ -1150,13 +1189,12 @@ string ResultParser::ParseResults(const Profile& profile, const SystemInformatio
|
|||
|
||||
for (size_t iResult = 0; iResult < vResults.size(); iResult++)
|
||||
{
|
||||
_Print("\n\nResults for timespan %d:\n", iResult + 1);
|
||||
_Print("\nResults for timespan %d:\n", iResult + 1);
|
||||
_Print("*******************************************************************************\n");
|
||||
|
||||
const Results& results = vResults[iResult];
|
||||
const TimeSpan& timeSpan = profile.GetTimeSpans()[iResult];
|
||||
|
||||
unsigned int ulProcCount = system.processorTopology._ulActiveProcCount;
|
||||
double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration
|
||||
|
||||
char szFloatBuffer[1024];
|
||||
|
@ -1182,9 +1220,7 @@ string ResultParser::ParseResults(const Profile& profile, const SystemInformatio
|
|||
_Print("request count:\t\t%u\n", timeSpan.GetRequestCount());
|
||||
}
|
||||
|
||||
_Print("proc count:\t\t%u\n", ulProcCount);
|
||||
_PrintCpuUtilization(results, system);
|
||||
|
||||
_PrintEffectiveDistributions(results);
|
||||
|
||||
_Print("\nTotal IO\n");
|
||||
|
@ -1198,7 +1234,6 @@ string ResultParser::ParseResults(const Profile& profile, const SystemInformatio
|
|||
|
||||
if (timeSpan.GetMeasureLatency())
|
||||
{
|
||||
_Print("\n\n");
|
||||
_PrintLatencyPercentiles(results);
|
||||
}
|
||||
|
||||
|
@ -1208,6 +1243,13 @@ string ResultParser::ParseResults(const Profile& profile, const SystemInformatio
|
|||
_DisplayETW(results.EtwMask, results.EtwEventCounters);
|
||||
_DisplayETWSessionInfo(results.EtwSessionInfo);
|
||||
}
|
||||
|
||||
// wait stats
|
||||
if (profile.GetVerboseStats())
|
||||
{
|
||||
_Print("\n");
|
||||
_PrintWaitStats(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -654,6 +654,161 @@ namespace UnitTests
|
|||
VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0);
|
||||
}
|
||||
|
||||
void CmdLineParserUnitTests::TestParseCmdLineBaseMaxTarget()
|
||||
{
|
||||
CmdLineParser p;
|
||||
struct Synchronization s = {};
|
||||
|
||||
{
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "testfile.dat" };
|
||||
VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo testfile.dat") == 0);
|
||||
|
||||
vector<TimeSpan> vSpans(profile.GetTimeSpans());
|
||||
VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1);
|
||||
|
||||
vector<Target> vTargets(vSpans[0].GetTargets());
|
||||
VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1);
|
||||
|
||||
// defaults = 0
|
||||
const auto& t(vTargets[0]);
|
||||
VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64) 0);
|
||||
VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64) 0);
|
||||
}
|
||||
|
||||
{
|
||||
// base 5MiB
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m", "testfile.dat" };
|
||||
VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m testfile.dat") == 0);
|
||||
|
||||
vector<TimeSpan> vSpans(profile.GetTimeSpans());
|
||||
VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1);
|
||||
|
||||
vector<Target> vTargets(vSpans[0].GetTargets());
|
||||
VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1);
|
||||
|
||||
const auto& t(vTargets[0]);
|
||||
VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024));
|
||||
VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64) 0);
|
||||
}
|
||||
|
||||
{
|
||||
// base 5MiB, length 1MiB -> 6MiB
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1m", "testfile.dat" };
|
||||
VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m:1m testfile.dat") == 0);
|
||||
|
||||
vector<TimeSpan> vSpans(profile.GetTimeSpans());
|
||||
VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1);
|
||||
|
||||
vector<Target> vTargets(vSpans[0].GetTargets());
|
||||
VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1);
|
||||
|
||||
const auto& t(vTargets[0]);
|
||||
VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024));
|
||||
VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64)(6 * 1024 * 1024));
|
||||
}
|
||||
|
||||
{
|
||||
// base 5MiB, max 6MiB
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m", "-f6m", "testfile.dat" };
|
||||
VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m -f6m testfile.dat") == 0);
|
||||
|
||||
vector<TimeSpan> vSpans(profile.GetTimeSpans());
|
||||
VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1);
|
||||
|
||||
vector<Target> vTargets(vSpans[0].GetTargets());
|
||||
VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1);
|
||||
|
||||
const auto& t(vTargets[0]);
|
||||
VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024));
|
||||
VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64)(6 * 1024 * 1024));
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify -f/-Bb:l together
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1m", "-f6m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify -B twice (2x b:l)
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1m", "-B5m:1m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify -B twice (b:l and b)
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1m", "-B5m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify -B twice (b and b)
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m", "-B5m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify -f twice (f and f)
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-f5m", "-f6m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// cannot specify max twice (b:l and f)
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1m", "-f6m", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// junk after -Bbase
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5mx", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// sep but no length
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// sep but junk length
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:j", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// sep but bad length spec
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1x", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
|
||||
{
|
||||
// sep but extra after length spec
|
||||
Profile profile;
|
||||
const char *argv[] = { "foo", "-B5m:1mx", "testfile.dat" };
|
||||
VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true);
|
||||
}
|
||||
}
|
||||
|
||||
void CmdLineParserUnitTests::TestParseCmdLineHintFlag()
|
||||
{
|
||||
CmdLineParser p;
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace UnitTests
|
|||
TEST_METHOD(TestParseCmdLineEtwUseSystemTimer);
|
||||
TEST_METHOD(TestParseCmdLineGroupAffinity);
|
||||
TEST_METHOD(TestParseCmdLineHintFlag);
|
||||
TEST_METHOD(TestParseCmdLineBaseMaxTarget);
|
||||
TEST_METHOD(TestParseCmdLineInterlockedSequential);
|
||||
TEST_METHOD(TestParseCmdLineInterlockedSequentialWithStride);
|
||||
TEST_METHOD(TestParseCmdLineIOPriority);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
|
|
|
@ -97,6 +97,28 @@ namespace UnitTests
|
|||
Histogram<int> h;
|
||||
h.Add(42);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1);
|
||||
|
||||
h.Add(42);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)2);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1);
|
||||
|
||||
h.Add(0);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)2);
|
||||
|
||||
// seal/reset count
|
||||
(void) h.GetMin();
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)2);
|
||||
|
||||
h.Add(0);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1);
|
||||
|
||||
(void) h.GetMin();
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1);
|
||||
}
|
||||
|
||||
void HistogramUnitTests::Test_Clear()
|
||||
|
@ -109,11 +131,25 @@ namespace UnitTests
|
|||
|
||||
void HistogramUnitTests::Test_MinMax()
|
||||
{
|
||||
Histogram<int> h;
|
||||
// use unsigned here for the sake of a compact empty "min"
|
||||
// signed would be ~0 as negative int
|
||||
Histogram<unsigned> h;
|
||||
h.Add(1);
|
||||
h.Add(3);
|
||||
VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)1);
|
||||
VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)3);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)2);
|
||||
|
||||
// seal/reset
|
||||
h.Add(2);
|
||||
VERIFY_ARE_EQUAL(h.GetMin(), 1);
|
||||
VERIFY_ARE_EQUAL(h.GetMax(), 2);
|
||||
VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)2);
|
||||
VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)2);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1);
|
||||
|
||||
// empty case
|
||||
h.Clear();
|
||||
VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)0);
|
||||
VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)0);
|
||||
}
|
||||
|
||||
void HistogramUnitTests::Test_GetPercentile()
|
||||
|
@ -122,7 +158,74 @@ namespace UnitTests
|
|||
h.Add(1);
|
||||
h.Add(2);
|
||||
h.Add(3);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 2);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 3);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3);
|
||||
|
||||
// single sample buckets
|
||||
for (int i = 1; i < 100; i++)
|
||||
{
|
||||
h.Add(i);
|
||||
}
|
||||
// double query at same val, forward, back and again
|
||||
// stresses iterator save correctness
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)99);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 10);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)99);
|
||||
|
||||
// multiple sample buckets - all same (2)
|
||||
for (int i = 1; i < 100; i++)
|
||||
{
|
||||
h.Add(i);
|
||||
h.Add(i);
|
||||
}
|
||||
// double query at same val, forward, back and again
|
||||
// stresses iterator save correctness
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)198);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 10);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)198);
|
||||
|
||||
// multiple sample buckets - extra weights on low end shift things lower
|
||||
for (int i = 1; i < 100; i++)
|
||||
{
|
||||
h.Add(i);
|
||||
|
||||
if (i < 50)
|
||||
{
|
||||
h.Add(i);
|
||||
}
|
||||
}
|
||||
// double query at same val, forward, back and again
|
||||
// stresses iterator save correctness
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)148);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 45);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 8);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 45);
|
||||
VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99);
|
||||
VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)148);
|
||||
}
|
||||
|
||||
void HistogramUnitTests::Test_GetMean()
|
||||
|
@ -418,8 +521,8 @@ namespace UnitTests
|
|||
// 2 group, 2 procs/group
|
||||
SystemInformation system;
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)2, (BYTE)2, (WORD)0, (KAFFINITY)0x3);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)2, (BYTE)2, (WORD)1, (KAFFINITY)0x3);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)2, (BYTE)2, (KAFFINITY)0x3);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)2, (BYTE)2, (KAFFINITY)0x3);
|
||||
|
||||
TimeSpan timeSpan;
|
||||
Profile profile;
|
||||
|
@ -436,16 +539,16 @@ namespace UnitTests
|
|||
|
||||
// shrink active mask
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)2, (BYTE)2, (WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)2, (BYTE)2, (WORD)1, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)2, (BYTE)2, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)2, (BYTE)2, (KAFFINITY)0x1);
|
||||
|
||||
// fail assignment to inactive procs
|
||||
VERIFY_IS_FALSE(profile.Validate(true, &system));
|
||||
|
||||
// shrink procs, still fail
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)1, (BYTE)1, (WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)1, (BYTE)1, (WORD)1, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)1, (BYTE)1, (KAFFINITY)0x1);
|
||||
|
||||
// now fail
|
||||
VERIFY_IS_FALSE(profile.Validate(true, &system));
|
||||
|
@ -460,7 +563,7 @@ namespace UnitTests
|
|||
|
||||
// shrink groups
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)1, (BYTE)1, (WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1);
|
||||
|
||||
// now fail
|
||||
VERIFY_IS_FALSE(profile.Validate(true, &system));
|
||||
|
@ -1070,4 +1173,57 @@ namespace UnitTests
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TopologyUnitTests::Test_MaskCount()
|
||||
{
|
||||
ULONG kaff_bits = sizeof(KAFFINITY) * 8;
|
||||
|
||||
// a complete enumeration could be interesting, but a nibble is enough to test the algorithm.
|
||||
// take the given mask and its width (ordinal distance to the upper 1), shift it through the
|
||||
// range of KAFFINITY to verify the popcnt is correct at all positions
|
||||
//
|
||||
// note that unique masks have msb/lsb set for all combinations of the interior bits. we don't
|
||||
// test "10" (0x2) as a mask, because it's not unique - its the same as the first shift-up of
|
||||
// "1" (0x1), etc.
|
||||
|
||||
struct {
|
||||
KAFFINITY mask;
|
||||
ULONG width;
|
||||
ULONG bits;
|
||||
} tests[] = { // msb ... lsb
|
||||
{ 0x1, 1, 1 }, // 1
|
||||
{ 0x3, 2, 2 }, // 11
|
||||
{ 0x5, 3, 2 }, // 101
|
||||
{ 0x7, 3, 3 }, // 111
|
||||
{ 0x9, 4, 2 }, // 1001
|
||||
{ 0xb, 4, 3 }, // 1011
|
||||
{ 0xd, 4, 3 }, // 1101
|
||||
{ 0xf, 4, 4 } // 1111
|
||||
};
|
||||
|
||||
for (const auto &test : tests)
|
||||
{
|
||||
KAFFINITY mask = test.mask;
|
||||
for (ULONG i = 0; i < kaff_bits - test.width; i++)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(mask), test.bits);
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ... and a few explicit true/false
|
||||
VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x0), (ULONG)1);
|
||||
VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x3), (ULONG)0);
|
||||
VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x5), (ULONG)3);
|
||||
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x0), (ULONG)0);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x3), (ULONG)2);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x5), (ULONG)2);
|
||||
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xffff), (ULONG)16);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfeef), (ULONG)14);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfeef00ff), (ULONG)22);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfe0000ff), (ULONG)15);
|
||||
VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x7e0000ff), (ULONG)14);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,8 +117,14 @@ namespace UnitTests
|
|||
TEST_CLASS(ThreadParametersUnitTests);
|
||||
TEST_METHOD(Test_AllocateAndFillBufferForTarget);
|
||||
};
|
||||
|
||||
class TopologyUnitTests : public WEX::TestClass<TopologyUnitTests>
|
||||
{
|
||||
public:
|
||||
TEST_CLASS(TopologyUnitTests);
|
||||
TEST_METHOD(Test_MaskCount);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: ThreadParameters::GetWriteBuffer
|
||||
// TODO: Target::GetRandomDataWriteBuffer();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
|
|
|
@ -92,10 +92,31 @@ namespace UnitTests
|
|||
SystemInformation system;
|
||||
system.sComputerName.clear();
|
||||
system.ResetTime();
|
||||
system.processorTopology._ulProcCount = 1;
|
||||
system.processorTopology._ulActiveProcCount = 1;
|
||||
system.processorTopology._vProcessorGroupInformation[0]._maximumProcessorCount = 1;
|
||||
system.processorTopology._vProcessorGroupInformation[0]._activeProcessorCount = 1;
|
||||
|
||||
// and power plan
|
||||
system.sActivePolicyName.clear();
|
||||
system.sActivePolicyGuid.clear();
|
||||
|
||||
system.processorTopology._ulProcessorCount = 1;
|
||||
system.processorTopology._ubPerformanceEfficiencyClass = 0;
|
||||
system.processorTopology._fSMT = false;
|
||||
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1);
|
||||
|
||||
ProcessorNumaInformation node;
|
||||
node._nodeNumber = 0;
|
||||
node._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorNumaInformation.clear();
|
||||
system.processorTopology._vProcessorNumaInformation.push_back(node);
|
||||
|
||||
ProcessorSocketInformation socket;
|
||||
socket._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorSocketInformation.clear();
|
||||
system.processorTopology._vProcessorSocketInformation.push_back(socket);
|
||||
|
||||
system.processorTopology._vProcessorCoreInformation.clear();
|
||||
system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)0, (KAFFINITY)0x1, (BYTE)0);
|
||||
|
||||
// finally, add the timespan to the profile and dump.
|
||||
profile.AddTimeSpan(timeSpan);
|
||||
|
@ -122,17 +143,25 @@ namespace UnitTests
|
|||
"\tcomputer name: \n"
|
||||
"\tstart time: \n"
|
||||
"\n"
|
||||
"\tcpu count:\t\t1\n"
|
||||
"\tcore count:\t\t1\n"
|
||||
"\tgroup count:\t\t1\n"
|
||||
"\tnode count:\t\t1\n"
|
||||
"\tsocket count:\t\t1\n"
|
||||
"\theterogeneous cores:\tn\n"
|
||||
"\n"
|
||||
"\tactive power scheme:\t\n"
|
||||
"\n"
|
||||
"Results for timespan 1:\n"
|
||||
"*******************************************************************************\n"
|
||||
"\n"
|
||||
"actual test time:\t120.00s\n"
|
||||
"thread count:\t\t1\n"
|
||||
"proc count:\t\t1\n"
|
||||
"\n"
|
||||
"CPU | Usage | User | Kernel | Idle\n"
|
||||
"-------------------------------------------\n"
|
||||
"----------------------------------------\n"
|
||||
" 0| 55.00%| 30.00%| 25.00%| 45.00%\n"
|
||||
"-------------------------------------------\n"
|
||||
"----------------------------------------\n"
|
||||
"avg.| 55.00%| 30.00%| 25.00%| 45.00%\n"
|
||||
"\n"
|
||||
"Total IO\n"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
DISKSPD.XSD HTML "..\\XmlProfileParser\\diskspd.xsd"
|
||||
|
||||
|
|
|
@ -52,22 +52,21 @@ namespace UnitTests
|
|||
double fTime = 120.0;
|
||||
results.ullTimeCount = PerfTimer::SecondsToPerfTime(fTime);
|
||||
|
||||
// First group has 1 core
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION systemProcessorInfo = {};
|
||||
// First group has 1 active cpu
|
||||
// 30% user, 45% idle, 25% non-idle kernel (45% + 25% = 70%)
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION systemProcessorInfo = { 0 };
|
||||
systemProcessorInfo.UserTime.QuadPart = static_cast<LONGLONG>(fTime * 30 * 100000);
|
||||
systemProcessorInfo.IdleTime.QuadPart = static_cast<LONGLONG>(fTime * 45 * 100000);
|
||||
systemProcessorInfo.KernelTime.QuadPart = static_cast<LONGLONG>(fTime * 70 * 100000);
|
||||
results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo);
|
||||
|
||||
// Second group has a maximum of 4 cores with 2 active
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION zeroSystemProcessorInfo = { 0 };
|
||||
zeroSystemProcessorInfo.UserTime.QuadPart = static_cast<LONGLONG>(fTime * 0 * 100000);
|
||||
zeroSystemProcessorInfo.IdleTime.QuadPart = static_cast<LONGLONG>(fTime * 100 * 100000);
|
||||
zeroSystemProcessorInfo.KernelTime.QuadPart = static_cast<LONGLONG>(fTime * 100 * 100000);
|
||||
results.vSystemProcessorPerfInfo.push_back(zeroSystemProcessorInfo);
|
||||
results.vSystemProcessorPerfInfo.push_back(zeroSystemProcessorInfo);
|
||||
results.vSystemProcessorPerfInfo.push_back(zeroSystemProcessorInfo);
|
||||
results.vSystemProcessorPerfInfo.push_back(zeroSystemProcessorInfo);
|
||||
// Second group has 2 active
|
||||
// 100% idle
|
||||
systemProcessorInfo.UserTime.QuadPart = static_cast<LONGLONG>(fTime * 0 * 100000);
|
||||
systemProcessorInfo.IdleTime.QuadPart = static_cast<LONGLONG>(fTime * 100 * 100000);
|
||||
systemProcessorInfo.KernelTime.QuadPart = static_cast<LONGLONG>(fTime * 100 * 100000);
|
||||
results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo);
|
||||
results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo);
|
||||
|
||||
// TODO: multiple target cases, full profile/result variations
|
||||
target.SetPath("testfile1.dat");
|
||||
|
@ -106,32 +105,41 @@ namespace UnitTests
|
|||
vector<Results> vResults;
|
||||
vResults.push_back(results);
|
||||
|
||||
// just throw away the computername and reset the timestamp - for the ut, it's
|
||||
// as useful (and simpler) to verify statics as anything else. Reconstruct
|
||||
// processor topo to a fixed example as well.
|
||||
// Just throw away the computername, pp and reset the timestamp - for the ut, it's
|
||||
// as useful (and simpler) to verify statics as anything else. Reconstruct the
|
||||
// processor topo to a fixed example as well. Note that the performance
|
||||
// efficiency class must be placed since it is calculated on the fly during
|
||||
// the actual GLPIEx enumeration. If we could shim GLPIEx ...
|
||||
SystemInformation system;
|
||||
system.ResetTime();
|
||||
system.sComputerName.clear();
|
||||
system.processorTopology._ulProcCount = 5;
|
||||
system.processorTopology._ulActiveProcCount = 3;
|
||||
system.sActivePolicyName.clear();
|
||||
system.sActivePolicyGuid.clear();
|
||||
|
||||
system.processorTopology._ulProcessorCount = 3;
|
||||
system.processorTopology._ubPerformanceEfficiencyClass = 1;
|
||||
system.processorTopology._fSMT = true;
|
||||
|
||||
system.processorTopology._vProcessorGroupInformation.clear();
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)1, (BYTE)1, (WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((BYTE)4, (BYTE)2, (WORD)1, (KAFFINITY)0x6);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)4, (BYTE)2, (KAFFINITY)0x3);
|
||||
|
||||
ProcessorNumaInformation node;
|
||||
node._nodeNumber = 0;
|
||||
node._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1);
|
||||
node._vProcessorMasks.emplace_back((WORD)1, (KAFFINITY)0x3);
|
||||
system.processorTopology._vProcessorNumaInformation.clear();
|
||||
system.processorTopology._vProcessorNumaInformation.emplace_back((DWORD)0, (WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorNumaInformation.emplace_back((DWORD)1, (WORD)1, (KAFFINITY)0x6);
|
||||
system.processorTopology._vProcessorNumaInformation.push_back(node);
|
||||
|
||||
ProcessorSocketInformation socket;
|
||||
socket._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1);
|
||||
socket._vProcessorMasks.emplace_back((WORD)1, (KAFFINITY)0x6);
|
||||
socket._vProcessorMasks.emplace_back((WORD)1, (KAFFINITY)0x3);
|
||||
system.processorTopology._vProcessorSocketInformation.clear();
|
||||
system.processorTopology._vProcessorSocketInformation.push_back(socket);
|
||||
|
||||
system.processorTopology._vProcessorHyperThreadInformation.clear();
|
||||
system.processorTopology._vProcessorHyperThreadInformation.emplace_back((WORD)0, (KAFFINITY)0x1);
|
||||
system.processorTopology._vProcessorHyperThreadInformation.emplace_back((WORD)1, (KAFFINITY)0x6);
|
||||
system.processorTopology._vProcessorCoreInformation.clear();
|
||||
system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)0, (KAFFINITY)0x1, (BYTE)0);
|
||||
system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)1, (KAFFINITY)0x3, (BYTE)1);
|
||||
|
||||
// finally, add the timespan to the profile and dump.
|
||||
profile.AddTimeSpan(timeSpan);
|
||||
|
@ -150,17 +158,20 @@ namespace UnitTests
|
|||
" <VersionDate>" DISKSPD_DATE_VERSION_STRING "</VersionDate>\n"
|
||||
" </Tool>\n"
|
||||
" <RunTime></RunTime>\n"
|
||||
" <ProcessorTopology>\n"
|
||||
" <PowerScheme Name=\"\" Guid=\"\"/>\n"
|
||||
" <ProcessorTopology Heterogeneous=\"true\">\n"
|
||||
" <Group Group=\"0\" MaximumProcessors=\"1\" ActiveProcessors=\"1\" ActiveProcessorMask=\"0x1\"/>\n"
|
||||
" <Group Group=\"1\" MaximumProcessors=\"4\" ActiveProcessors=\"2\" ActiveProcessorMask=\"0x6\"/>\n"
|
||||
" <Node Node=\"0\" Group=\"0\" Processors=\"0x1\"/>\n"
|
||||
" <Node Node=\"1\" Group=\"1\" Processors=\"0x6\"/>\n"
|
||||
" <Socket>\n"
|
||||
" <Group Group=\"0\" Processors=\"0x1\"/>\n"
|
||||
" <Group Group=\"1\" Processors=\"0x6\"/>\n"
|
||||
" <Group Group=\"1\" MaximumProcessors=\"4\" ActiveProcessors=\"2\" ActiveProcessorMask=\"0x3\"/>\n"
|
||||
" <Node Node=\"0\">\n"
|
||||
" <Group Group=\"0\" Mask=\"0x1\"/>\n"
|
||||
" <Group Group=\"1\" Mask=\"0x3\"/>\n"
|
||||
" </Node>\n"
|
||||
" <Socket Socket=\"0\">\n"
|
||||
" <Group Group=\"0\" Mask=\"0x1\"/>\n"
|
||||
" <Group Group=\"1\" Mask=\"0x3\"/>\n"
|
||||
" </Socket>\n"
|
||||
" <HyperThread Group=\"0\" Processors=\"0x1\"/>\n"
|
||||
" <HyperThread Group=\"1\" Processors=\"0x6\"/>\n"
|
||||
" <Core Group=\"0\" Core=\"0\" Mask=\"0x1\" EfficiencyClass=\"0\"/>\n"
|
||||
" <Core Group=\"1\" Core=\"0\" Mask=\"0x3\" EfficiencyClass=\"1\"/>\n"
|
||||
" </ProcessorTopology>\n"
|
||||
" </System>\n"
|
||||
" <Profile>\n"
|
||||
|
@ -217,7 +228,11 @@ namespace UnitTests
|
|||
" <ProcCount>3</ProcCount>\n"
|
||||
" <CpuUtilization>\n"
|
||||
" <CPU>\n"
|
||||
" <Socket>0</Socket>\n"
|
||||
" <Node>0</Node>\n"
|
||||
" <Group>0</Group>\n"
|
||||
" <Core>0</Core>\n"
|
||||
" <EfficiencyClass>0</EfficiencyClass>\n"
|
||||
" <Id>0</Id>\n"
|
||||
" <UsagePercent>55.00</UsagePercent>\n"
|
||||
" <UserPercent>30.00</UserPercent>\n"
|
||||
|
@ -225,16 +240,24 @@ namespace UnitTests
|
|||
" <IdlePercent>45.00</IdlePercent>\n"
|
||||
" </CPU>\n"
|
||||
" <CPU>\n"
|
||||
" <Socket>0</Socket>\n"
|
||||
" <Node>0</Node>\n"
|
||||
" <Group>1</Group>\n"
|
||||
" <Id>1</Id>\n"
|
||||
" <Core>0</Core>\n"
|
||||
" <EfficiencyClass>1</EfficiencyClass>\n"
|
||||
" <Id>0</Id>\n"
|
||||
" <UsagePercent>0.00</UsagePercent>\n"
|
||||
" <UserPercent>0.00</UserPercent>\n"
|
||||
" <KernelPercent>0.00</KernelPercent>\n"
|
||||
" <IdlePercent>100.00</IdlePercent>\n"
|
||||
" </CPU>\n"
|
||||
" <CPU>\n"
|
||||
" <Socket>0</Socket>\n"
|
||||
" <Node>0</Node>\n"
|
||||
" <Group>1</Group>\n"
|
||||
" <Id>2</Id>\n"
|
||||
" <Core>0</Core>\n"
|
||||
" <EfficiencyClass>1</EfficiencyClass>\n"
|
||||
" <Id>1</Id>\n"
|
||||
" <UsagePercent>0.00</UsagePercent>\n"
|
||||
" <UserPercent>0.00</UserPercent>\n"
|
||||
" <KernelPercent>0.00</KernelPercent>\n"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include "Common.h"
|
||||
#include "Version.h"
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
|
|
|
@ -200,6 +200,26 @@ bool XmlProfileParser::ParseFile(const char *pszPath, Profile *pProfile, vector<
|
|||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
bool b;
|
||||
hr = _GetBool(spXmlDoc, "//Profile/VerboseStats", &b);
|
||||
if (SUCCEEDED(hr) && (hr != S_FALSE))
|
||||
{
|
||||
pProfile->SetVerboseStats(b);
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD i;
|
||||
hr = _GetDWORD(spXmlDoc, "//Profile/ExperimentFlags", &i);
|
||||
if (SUCCEEDED(hr) && (hr != S_FALSE))
|
||||
{
|
||||
g_ExperimentFlags = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD i;
|
||||
|
|
|
@ -17,64 +17,121 @@
|
|||
<!-- file / disk -->
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
|
||||
<!-- Random Distributions
|
||||
|
||||
Note use of typed elements to implement basic validation. Exactly one type of distribution
|
||||
is allowed. Range specification is cumulative per command line model and validated after load.
|
||||
|
||||
-rdabs10/50000:10/20
|
||||
<Absolute>
|
||||
<Range IO="10">50000</Range>
|
||||
<Range IO="10">20</Range>
|
||||
</Absolute>
|
||||
|
||||
-rdpct10/50:10/20
|
||||
<Percent>
|
||||
<Range IO="10">50</Range>
|
||||
<Range IO="10">20</Range>
|
||||
</Percent>
|
||||
|
||||
-->
|
||||
|
||||
<xs:element name="Distribution" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
<xs:element name="Percent" minOccurs="1" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Range" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="PercentNZ">
|
||||
<xs:attribute type="Percent" name="IO" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Absolute" minOccurs="1" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Range" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedLong">
|
||||
<xs:attribute type="Percent" name="IO" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<!-- string _sPath -->
|
||||
<xs:element name="Path" type="xs:string" minOccurs="1" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Path" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwBlockSize -->
|
||||
<xs:element name="BlockSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="BlockSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullStrideSize -->
|
||||
<xs:element name="StrideSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="StrideSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<xs:element name="InterlockedSequential" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="InterlockedSequential" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullBaseFileOffset -->
|
||||
<xs:element name="BaseFileOffset" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="BaseFileOffset" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fSequentialScan (open file with the FILE_FLAG_SEQUENTIAL_SCAN flag) -->
|
||||
<xs:element name="SequentialScan" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="SequentialScan" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fRandomAccess (open file with the FILE_FLAG_RANDOM_ACCESS flag) -->
|
||||
<xs:element name="RandomAccess" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="RandomAccess" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fTemporaryFile (open file with the FILE_ATTRIBUTE_TEMPORARY flag) -->
|
||||
<xs:element name="TemporaryFile" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="TemporaryFile" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fUseLargePages (Use large pages for IO buffers) -->
|
||||
<xs:element name="UseLargePages" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="UseLargePages" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwRequestCount -->
|
||||
<!-- -o<count> number of overlapped I/O requests per file per thread
|
||||
(1=synchronous I/O, unless more than 1 thread is specified with -F) [default=2]-->
|
||||
<xs:element name="RequestCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="RequestCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullRandom
|
||||
-r<align>[K|M|G|b] random I/O aligned to <align> bytes (doesn't make sense with -s)
|
||||
<align> can be stated in bytes/KB/MB/GB/blocks [default access=sequential, default alignment=block size] -->
|
||||
<xs:element name="Random" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Random" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL DisableAllCache combined DisableOSCache & WriteThrough (compat) -->
|
||||
<xs:element name="DisableAllCache" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="DisableAllCache" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL DisableLocalCache -->
|
||||
<xs:element name="DisableLocalCache" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="DisableLocalCache" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL DisableOSCache -->
|
||||
<xs:element name="DisableOSCache" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="DisableOSCache" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL WriteThrough -->
|
||||
<xs:element name="WriteThrough" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="WriteThrough" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL MemoryMappedIo -->
|
||||
<xs:element name="MemoryMappedIo" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="MemoryMappedIo" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- enum FlushType, only has effect with memory mapped writes -->
|
||||
<xs:element name="FlushType" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="ViewOfFile"></xs:enumeration>
|
||||
<xs:enumeration value="NonVolatileMemory"></xs:enumeration>
|
||||
<xs:enumeration value="NonVolatileMemoryNoDrain"></xs:enumeration>
|
||||
<xs:enumeration value="ViewOfFile"/>
|
||||
<xs:enumeration value="NonVolatileMemory"/>
|
||||
<xs:enumeration value="NonVolatileMemoryNoDrain"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
|
@ -86,9 +143,9 @@
|
|||
<xs:element name="Pattern" minOccurs="1" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="sequential"></xs:enumeration>
|
||||
<xs:enumeration value="zero"></xs:enumeration>
|
||||
<xs:enumeration value="random"></xs:enumeration>
|
||||
<xs:enumeration value="sequential"/>
|
||||
<xs:enumeration value="zero"/>
|
||||
<xs:enumeration value="random"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
|
@ -97,8 +154,8 @@
|
|||
<xs:element name="RandomDataSource" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="SizeInBytes" type="xs:unsignedLong" minOccurs="1" maxOccurs="1"></xs:element>
|
||||
<xs:element name="FilePath" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="SizeInBytes" type="xs:unsignedLong" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="FilePath" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
@ -108,43 +165,62 @@
|
|||
</xs:element>
|
||||
|
||||
<!-- DWORD dwBurstSize (number of IOs in a burst) -->
|
||||
<xs:element name="BurstSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="BurstSize" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwThinkTime (time to pause before issuing the next burst of IOs) -->
|
||||
<xs:element name="ThinkTime" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="ThinkTime" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwThroughput (in bytes per millisecond); this can not be specified when using completion routines -->
|
||||
<xs:element name="Throughput" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Throughput" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedInt">
|
||||
<xs:attribute name="unit" default="BPMS">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="IOPS"/>
|
||||
<xs:enumeration value="BPMS"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<!-- DWORD dwThreadsPerFile -->
|
||||
<xs:element name="ThreadsPerFile" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="ThreadsPerFile" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullFileSize -->
|
||||
<!-- used by the -c (create file) switch-->
|
||||
<xs:element name="FileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="FileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullMaxFileSize -->
|
||||
<xs:element name="MaxFileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="MaxFileSize" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 ulWriteRatio -->
|
||||
<xs:element name="WriteRatio" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="WriteRatio" type="Percent" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 ulRandomRatio -->
|
||||
<!-- Note: RandomRatio should only ever be between 1 and 99 - 0 is <StrideSize> in isolation, and 100 is <Random> in isolation -->
|
||||
<xs:element name="RandomRatio" type="PercentNZNM" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fParallelAsyncIO
|
||||
-p start async (overlapped) I/O operations with the same offset (makes sense only with -o2 or grater) -->
|
||||
<xs:element name="ParallelAsyncIO" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
-p start async (overlapped) I/O operations with the same offset (makes sense only with -o2 or greater) -->
|
||||
<xs:element name="ParallelAsyncIO" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT64 ullThreadStride -->
|
||||
<xs:element name="ThreadStride" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="ThreadStride" type="xs:unsignedLong" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- 0 - not set, 1 - very low, 2 - low, 3 - normal -->
|
||||
<xs:element name="IOPriority" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="IOPriority" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- Weight to apply to this target on the specified threads - only valid when timespan
|
||||
specifies ThreadCount and RequestCount, no cmd line equivalent. The actual weight
|
||||
given to this target will depend on the weights that other targets specify. The
|
||||
weight for this target is Weight / sum(Weight for all targets). If the total weight
|
||||
is 100 and the weight for this target is 30, then 30% of the IOs will be to this target. -->
|
||||
<xs:element name="Weight" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Weight" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- Threads to use - only valid when timespan specifies ThreadCount, no cmd line equivalent.
|
||||
If a weight is specified it will override the overall weight for the target. If no
|
||||
|
@ -156,8 +232,8 @@
|
|||
<xs:element name="ThreadTarget" minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Thread" type="xs:unsignedInt" minOccurs="1" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Weight" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Thread" type="xs:unsignedInt" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="Weight" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
@ -174,39 +250,39 @@
|
|||
</xs:element>
|
||||
|
||||
<!-- UINT32 ulDuration -->
|
||||
<xs:element name="Duration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Duration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 ulWarmUp -->
|
||||
<xs:element name="Warmup" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Warmup" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 ulCoolDown -->
|
||||
<xs:element name="Cooldown" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Cooldown" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 ulRandSeed
|
||||
-z set random seed [default=0 if parameter not provided, GetTickCount() if value not provided] -->
|
||||
<xs:element name="RandSeed" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="RandSeed" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fRandomWriteData -->
|
||||
<xs:element name="RandomWriteData" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="RandomWriteData" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwThreadCount
|
||||
-F<count> total number of threads (cannot be used with -t) this cannot be used if per-file thread count is provided -->
|
||||
<xs:element name="ThreadCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="ThreadCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwRequestCount
|
||||
-O<count> total number of requests per thread - for use with -F -->
|
||||
<xs:element name="RequestCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="RequestCount" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fGroupAffinity -->
|
||||
<xs:element name="GroupAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="GroupAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- UINT32 *puAffinity -->
|
||||
<xs:element name="Affinity" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="AffinityAssignment" type="xs:unsignedInt" minOccurs="1" maxOccurs="unbounded"></xs:element>
|
||||
<xs:element name="AffinityGroupAssignment" type="AffinityGroupAssignment" minOccurs="1" maxOccurs="unbounded"></xs:element>
|
||||
<xs:element name="AffinityAssignment" type="xs:unsignedInt" minOccurs="1" maxOccurs="unbounded"/>
|
||||
<xs:element name="AffinityGroupAssignment" type="AffinityGroupAssignment" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
@ -214,16 +290,16 @@
|
|||
|
||||
<!-- BOOL fDisableAffinity
|
||||
-n disable affinity (cannot be used with -a) -->
|
||||
<xs:element name="DisableAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="DisableAffinity" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- BOOL fCompletionRoutines -->
|
||||
<!-- TODO: this should be decided on a target level -->
|
||||
<xs:element name="CompletionRoutines" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="CompletionRoutines" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<xs:element name="MeasureLatency" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="MeasureLatency" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<xs:element name="CalculateIopsStdDev" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="IoBucketDuration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="CalculateIopsStdDev" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="IoBucketDuration" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
@ -232,16 +308,20 @@
|
|||
</xs:element>
|
||||
|
||||
<!-- BOOL bVerbose -->
|
||||
<xs:element name="Verbose" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Verbose" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="VerboseStats" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- DWORD dwProgress -->
|
||||
<xs:element name="Progress" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Progress" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<!-- Experimental behavior flags -->
|
||||
<xs:element name="ExperimentFlags" type="xs:unsignedInt" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
<xs:element name="ResultFormat" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="text"></xs:enumeration>
|
||||
<xs:enumeration value="xml"></xs:enumeration>
|
||||
<xs:enumeration value="text"/>
|
||||
<xs:enumeration value="xml"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
|
@ -251,29 +331,29 @@
|
|||
<xs:complexType>
|
||||
<xs:all>
|
||||
<!-- BOOL bProcess -->
|
||||
<xs:element name="Process" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Process" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bThread -->
|
||||
<xs:element name="Thread" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Thread" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bImageLoad -->
|
||||
<xs:element name="ImageLoad" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="ImageLoad" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bDiskIO -->
|
||||
<xs:element name="DiskIO" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="DiskIO" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bMemoryPageFaults -->
|
||||
<xs:element name="MemoryPageFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="MemoryPageFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bMemoryHardFaults -->
|
||||
<xs:element name="MemoryHardFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="MemoryHardFaults" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bNetwork -->
|
||||
<xs:element name="Network" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Network" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bRegistry -->
|
||||
<xs:element name="Registry" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="Registry" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bUsePagedMemory -->
|
||||
<xs:element name="UsePagedMemory" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="UsePagedMemory" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bUsePerfTimer -->
|
||||
<xs:element name="UsePerfTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="UsePerfTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bUseSystemTimer -->
|
||||
<xs:element name="UseSystemTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="UseSystemTimer" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<!-- BOOL bUseCyclesCounter -->
|
||||
<xs:element name="UseCyclesCounter" type="xs:boolean" minOccurs="0" maxOccurs="1"></xs:element>
|
||||
<xs:element name="UseCyclesCounter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
@ -283,9 +363,9 @@
|
|||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<!-- if the same path exists in multiple time spans, the max size will be used -->
|
||||
<xs:enumeration value="UseMaxSize"></xs:enumeration>
|
||||
<xs:enumeration value="CreateOnlyFilesWithConstantSizes"></xs:enumeration>
|
||||
<xs:enumeration value="CreateOnlyFilesWithConstantOrZeroSizes"></xs:enumeration>
|
||||
<xs:enumeration value="UseMaxSize"/>
|
||||
<xs:enumeration value="CreateOnlyFilesWithConstantSizes"/>
|
||||
<xs:enumeration value="CreateOnlyFilesWithConstantOrZeroSizes"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
|
@ -298,4 +378,23 @@
|
|||
<xs:attribute name="Group" type="xs:unsignedInt"/>
|
||||
<xs:attribute name="Processor" type="xs:unsignedInt"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="Percent">
|
||||
<xs:restriction base="xs:unsignedInt">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="PercentNZ">
|
||||
<xs:restriction base="xs:unsignedInt">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="PercentNZNM">
|
||||
<xs:restriction base="xs:unsignedInt">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="99"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
|
|
|
@ -31,15 +31,22 @@ SOFTWARE.
|
|||
|
||||
// TODO: refactor to a single function shared with the ResultParser
|
||||
char printBuffer[4096] = {};
|
||||
|
||||
void XmlResultParser::_PrintV(const char *format, va_list listArg)
|
||||
{
|
||||
_sResult.append(_indent, ' ');
|
||||
vsprintf_s(printBuffer, _countof(printBuffer), format, listArg);
|
||||
_sResult += printBuffer;
|
||||
}
|
||||
|
||||
void XmlResultParser::_Print(const char *format, ...)
|
||||
{
|
||||
assert(nullptr != format);
|
||||
va_list listArg;
|
||||
va_start(listArg, format);
|
||||
_sResult.append(_indent, ' ');
|
||||
vsprintf_s(printBuffer, _countof(printBuffer), format, listArg);
|
||||
|
||||
_PrintV(format, listArg);
|
||||
va_end(listArg);
|
||||
_sResult += printBuffer;
|
||||
}
|
||||
|
||||
void XmlResultParser::_PrintInc(const char *format, ...)
|
||||
|
@ -51,7 +58,7 @@ void XmlResultParser::_PrintInc(const char *format, ...)
|
|||
// Print & Increment Indent
|
||||
// e.g., <StartOfSection>
|
||||
|
||||
_Print(format, listArg);
|
||||
_PrintV(format, listArg);
|
||||
_indent += 2;
|
||||
va_end(listArg);
|
||||
}
|
||||
|
@ -66,7 +73,7 @@ void XmlResultParser::_PrintDec(const char *format, ...)
|
|||
// e.g., </EndOfSection>
|
||||
|
||||
_indent -= 2;
|
||||
_Print(format, listArg);
|
||||
_PrintV(format, listArg);
|
||||
va_end(listArg);
|
||||
}
|
||||
|
||||
|
@ -253,10 +260,11 @@ void XmlResultParser::_PrintETW(struct ETWMask ETWMask, struct ETWEventCounters
|
|||
|
||||
void XmlResultParser::_PrintCpuUtilization(const Results& results, const SystemInformation& system)
|
||||
{
|
||||
size_t ulProcCount = results.vSystemProcessorPerfInfo.size();
|
||||
size_t ulBaseProc = 0;
|
||||
size_t ulActiveProcCount = 0;
|
||||
size_t ulNumGroups = system.processorTopology._vProcessorGroupInformation.size();
|
||||
const auto& topo = system.processorTopology;
|
||||
size_t procCount = results.vSystemProcessorPerfInfo.size();
|
||||
size_t baseProc = 0;
|
||||
BYTE efficiencyClass = 0;
|
||||
BYTE processorCore = 0;
|
||||
|
||||
_PrintInc("<CpuUtilization>\n");
|
||||
|
||||
|
@ -265,62 +273,51 @@ void XmlResultParser::_PrintCpuUtilization(const Results& results, const SystemI
|
|||
double totalUserTime = 0;
|
||||
double totalKrnlTime = 0;
|
||||
|
||||
for (unsigned int ulGroup = 0; ulGroup < ulNumGroups; ulGroup++) {
|
||||
const ProcessorGroupInformation *pGroup = &system.processorTopology._vProcessorGroupInformation[ulGroup];
|
||||
for (const auto& group : topo._vProcessorGroupInformation) {
|
||||
|
||||
// System has multiple groups but we only have counters for the first one
|
||||
if (ulBaseProc >= ulProcCount) {
|
||||
break;
|
||||
}
|
||||
// Sanity assert - results are sized to the sum of active processors
|
||||
assert(baseProc + group._activeProcessorCount <= procCount);
|
||||
|
||||
for (unsigned int ulProcessor = 0; ulProcessor < pGroup->_maximumProcessorCount; ulProcessor++) {
|
||||
double idleTime;
|
||||
double userTime;
|
||||
double krnlTime;
|
||||
double thisTime;
|
||||
for (BYTE processor = 0; processor < group._activeProcessorCount; processor++) {
|
||||
|
||||
if (!pGroup->IsProcessorActive((BYTE)ulProcessor)) {
|
||||
continue;
|
||||
}
|
||||
long long fTime = results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart +
|
||||
results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart;
|
||||
|
||||
long long fTime = results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].KernelTime.QuadPart +
|
||||
results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].UserTime.QuadPart;
|
||||
|
||||
idleTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].IdleTime.QuadPart / fTime;
|
||||
krnlTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].KernelTime.QuadPart / fTime;
|
||||
userTime = 100.0 * results.vSystemProcessorPerfInfo[ulBaseProc + ulProcessor].UserTime.QuadPart / fTime;
|
||||
|
||||
thisTime = (krnlTime + userTime) - idleTime;
|
||||
double idleTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].IdleTime.QuadPart / fTime;
|
||||
double krnlTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart / fTime;
|
||||
double userTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart / fTime;
|
||||
double usedTime = (krnlTime - idleTime) + userTime;
|
||||
|
||||
_PrintInc("<CPU>\n");
|
||||
_Print("<Group>%d</Group>\n", ulGroup);
|
||||
_Print("<Id>%d</Id>\n", ulProcessor);
|
||||
_Print("<UsagePercent>%.2f</UsagePercent>\n", thisTime);
|
||||
_Print("<Socket>%d</Socket>\n", topo.GetSocketOfProcessor(group._groupNumber, processor));
|
||||
_Print("<Node>%d</Node>\n", topo.GetNumaOfProcessor(group._groupNumber, processor));
|
||||
_Print("<Group>%d</Group>\n", group._groupNumber);
|
||||
processorCore = topo.GetCoreOfProcessor(group._groupNumber, processor, efficiencyClass);
|
||||
_Print("<Core>%d</Core>\n", processorCore);
|
||||
_Print("<EfficiencyClass>%d</EfficiencyClass>\n", efficiencyClass);
|
||||
_Print("<Id>%d</Id>\n", processor);
|
||||
_Print("<UsagePercent>%.2f</UsagePercent>\n", usedTime);
|
||||
_Print("<UserPercent>%.2f</UserPercent>\n", userTime);
|
||||
_Print("<KernelPercent>%.2f</KernelPercent>\n", krnlTime - idleTime);
|
||||
_Print("<IdlePercent>%.2f</IdlePercent>\n", idleTime);
|
||||
_PrintDec("</CPU>\n");
|
||||
|
||||
busyTime += thisTime;
|
||||
busyTime += usedTime;
|
||||
totalIdleTime += idleTime;
|
||||
totalUserTime += userTime;
|
||||
totalKrnlTime += krnlTime;
|
||||
|
||||
ulActiveProcCount++;
|
||||
}
|
||||
|
||||
ulBaseProc += pGroup->_maximumProcessorCount;
|
||||
baseProc += group._activeProcessorCount;
|
||||
}
|
||||
|
||||
if (ulActiveProcCount == 0) {
|
||||
ulActiveProcCount = 1;
|
||||
}
|
||||
assert(baseProc == procCount);
|
||||
|
||||
_PrintInc("<Average>\n");
|
||||
_Print("<UsagePercent>%.2f</UsagePercent>\n", busyTime / ulActiveProcCount);
|
||||
_Print("<UserPercent>%.2f</UserPercent>\n", totalUserTime / ulActiveProcCount);
|
||||
_Print("<KernelPercent>%.2f</KernelPercent>\n", (totalKrnlTime - totalIdleTime) / ulActiveProcCount);
|
||||
_Print("<IdlePercent>%.2f</IdlePercent>\n", totalIdleTime / ulActiveProcCount);
|
||||
_Print("<UsagePercent>%.2f</UsagePercent>\n", busyTime / procCount);
|
||||
_Print("<UserPercent>%.2f</UserPercent>\n", totalUserTime / procCount);
|
||||
_Print("<KernelPercent>%.2f</KernelPercent>\n", (totalKrnlTime - totalIdleTime) / procCount);
|
||||
_Print("<IdlePercent>%.2f</IdlePercent>\n", totalIdleTime / procCount);
|
||||
_PrintDec("</Average>\n");
|
||||
|
||||
_PrintDec("</CpuUtilization>\n");
|
||||
|
@ -412,7 +409,11 @@ void XmlResultParser::_PrintLatencyPercentiles(const Results& results)
|
|||
}
|
||||
}
|
||||
|
||||
_PrintInc("<Latency>\n");
|
||||
_PrintInc("<Latency ReadHistoBuckets=\"%lu\" WriteHistoBuckets=\"%lu\" TotalHistoBuckets=\"%lu\">\n",
|
||||
readLatencyHistogram.GetSampleBuckets(),
|
||||
writeLatencyHistogram.GetSampleBuckets(),
|
||||
totalLatencyHistogram.GetSampleBuckets());
|
||||
|
||||
if (readLatencyHistogram.GetSampleSize() > 0)
|
||||
{
|
||||
_Print("<AverageReadMilliseconds>%.3f</AverageReadMilliseconds>\n", readLatencyHistogram.GetAvg() / 1000);
|
||||
|
@ -505,6 +506,25 @@ string XmlResultParser::ParseProfile(const Profile& profile)
|
|||
return _sResult;
|
||||
}
|
||||
|
||||
void XmlResultParser::_PrintWaitStats(const ThreadResults &threadResult)
|
||||
{
|
||||
_PrintInc("<WaitStatistics>\n");
|
||||
_Print("<CompletionWait>%llu</CompletionWait>\n", threadResult.WaitStats.Wait);
|
||||
_Print("<ThrottleWait>%llu</ThrottleWait>\n", threadResult.WaitStats.ThrottleWait);
|
||||
_Print("<ThrottleSleep>%llu</ThrottleSleep>\n", threadResult.WaitStats.ThrottleSleep);
|
||||
_Print("<Lookaside>%llu</Lookaside>\n", threadResult.WaitStats.Lookaside);
|
||||
_Print("<LookasideCompletion>%llu %llu %llu %llu %llu %llu %llu %llu</LookasideCompletion>\n",
|
||||
threadResult.WaitStats.LookasideCompletion[0],
|
||||
threadResult.WaitStats.LookasideCompletion[1],
|
||||
threadResult.WaitStats.LookasideCompletion[2],
|
||||
threadResult.WaitStats.LookasideCompletion[3],
|
||||
threadResult.WaitStats.LookasideCompletion[4],
|
||||
threadResult.WaitStats.LookasideCompletion[5],
|
||||
threadResult.WaitStats.LookasideCompletion[6],
|
||||
threadResult.WaitStats.LookasideCompletion[7]);
|
||||
_PrintDec("</WaitStatistics>\n");
|
||||
}
|
||||
|
||||
string XmlResultParser::ParseResults(const Profile& profile, const SystemInformation& system, vector<Results> vResults)
|
||||
{
|
||||
_sResult.clear();
|
||||
|
@ -526,12 +546,11 @@ string XmlResultParser::ParseResults(const Profile& profile, const SystemInforma
|
|||
// There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file.
|
||||
// In the latter case vThreadResults.size() == number of threads per file * file count
|
||||
size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size();
|
||||
unsigned int ulProcCount = system.processorTopology._ulActiveProcCount;
|
||||
|
||||
_Print("<TestTimeSeconds>%.2f</TestTimeSeconds>\n", fTime);
|
||||
_Print("<ThreadCount>%u</ThreadCount>\n", ulThreadCnt);
|
||||
_Print("<RequestCount>%u</RequestCount>\n", timeSpan.GetRequestCount());
|
||||
_Print("<ProcCount>%u</ProcCount>\n", ulProcCount);
|
||||
_Print("<ProcCount>%u</ProcCount>\n", system.processorTopology._ulProcessorCount);
|
||||
|
||||
_PrintCpuUtilization(results, system);
|
||||
|
||||
|
@ -570,6 +589,10 @@ string XmlResultParser::ParseResults(const Profile& profile, const SystemInforma
|
|||
}
|
||||
_PrintDec("</Target>\n");
|
||||
}
|
||||
if (profile.GetVerboseStats())
|
||||
{
|
||||
_PrintWaitStats(threadResults);
|
||||
}
|
||||
_PrintDec("</Thread>\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -85,7 +85,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -98,7 +97,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -112,7 +110,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -128,7 +125,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -90,11 +90,10 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -104,11 +103,10 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -119,13 +117,12 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -136,13 +133,12 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -74,7 +74,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -87,7 +86,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -101,7 +99,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -117,7 +114,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -85,7 +85,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -98,7 +97,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -112,7 +110,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -128,7 +125,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -85,7 +85,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -98,7 +97,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -112,7 +110,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -128,7 +125,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -114,7 +114,7 @@
|
|||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -128,7 +128,7 @@
|
|||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -146,7 +146,7 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -164,7 +164,7 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -129,7 +129,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -147,7 +147,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -165,7 +165,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -129,7 +129,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -147,7 +147,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -165,7 +165,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -129,7 +129,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -147,7 +147,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -165,7 +165,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -129,7 +129,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -147,7 +147,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -165,7 +165,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -39,26 +39,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -129,7 +129,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -147,7 +147,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -165,7 +165,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -28,27 +28,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -85,7 +85,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -98,7 +97,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -112,7 +110,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -128,7 +125,6 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -29,27 +29,27 @@
|
|||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -89,7 +89,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -106,7 +105,6 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -124,7 +122,6 @@
|
|||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -144,7 +141,6 @@
|
|||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -154,10 +150,10 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\XmlResultParser\XmlResultParser.cpp" />
|
||||
<ClCompile Include="..\..\XmlResultParser\xmlresultparser.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\Common\XmlResultParser.h" />
|
||||
<ClInclude Include="..\..\Common\xmlresultparser.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
Загрузка…
Ссылка в новой задаче