* 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:
Dan Lovinger 2024-06-13 13:14:31 -07:00 коммит произвёл GitHub
Родитель 206bae568c
Коммит 2ac91a462b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
41 изменённых файлов: 13862 добавлений и 12590 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

52
Common/Version.h Normal file
Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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">