in CmdLineParser/CmdLineParser.cpp [580:716]
bool CmdLineParser::_ParseRandomDistribution(const char *arg, vector<Target>& vTargets)
{
vector<DistributionRange> vOr;
DistributionType dType;
bool fOk = false;
UINT32 pctAcc = 0, pctCur; // accumulated/cur pct io
UINT64 targetAcc = 0, targetCur; // accumulated/cur target
if (!strncmp(arg, "pct", 3))
{
dType = DistributionType::Percent;
}
else if (strncmp(arg, "abs", 3))
{
fprintf(stderr, "Unrecognized random distribution type\n");
return false;
}
else
{
dType = DistributionType::Absolute;
}
arg += 3;
//
// Parse pairs of
//
// * pct: percentage/target percentage
// * abs: percentage/absolute range of target
//
// Ex: 90/10:5/5 => [0,90) -> [0, 10) :: [90, 95) -> [10, 15)
// a remainder of [95, 100) -> [15, 100) would be applied.
//
// Percentages are cumulative and successively define the span of
// the preceding definition. Absolute ranges are also cumulative:
// 10/1G:90/1G puts 90% of accesses in the second 1G range of the
// target.
//
// A single percentage can be 100 but is of limited value since it
// would only be valid as a single element distribution.
//
// Basic numeric validations are done here (similar to XSD for XML).
// Cross validation with other workload parameters (blocksize) and whole
// distribution validation is delayed to common code.
//
while (true)
{
// Consume IO% integer
fOk = Util::ParseUInt(arg, pctCur, arg);
if (!fOk)
{
fprintf(stderr, "Invalid integer IO%%: must be > 0 and <= %u\n", 100 - pctAcc);
return false;
}
// hole is ok
else if (pctCur > 100)
{
fprintf(stderr, "Invalid IO%% %u: must be >= 0 and <= %u\n", pctCur, 100 - pctAcc);
return false;
}
// Expect separator
if (*arg++ != '/')
{
fprintf(stderr, "Expected / separator after %u\n", pctCur);
return false;
}
// Consume Target%/Absolute range integer
if (dType == DistributionType::Percent)
{
// Percent specification
fOk = Util::ParseUInt(arg, targetCur, arg);
if (!fOk)
{
fprintf(stderr, "Invalid integer Target%%: must be > 0 and <= %I64u\n", 100 - targetAcc);
return false;
}
// no hole
else if (targetCur == 0 || targetCur > 100)
{
fprintf(stderr, "Invalid Target%% %I64u: must be > 0 and <= %I64u\n", targetCur, 100 - targetAcc);
return false;
}
}
else
{
// Size specification
fOk = CmdLineParser::_GetSizeInBytes(arg, targetCur, &arg);
if (!fOk)
{
// error already emitted
return fOk;
}
if (targetCur == 0)
{
fprintf(stderr, "Invalid zero length target range\n");
return false;
}
}
// Add range from [accumulator - accumulator + current) => ...
// Note that zero pctCur indicates a hole where no IO is desired - this is recorded
// for fidelity of display/profile but will never match on lookup, as intended.
vOr.emplace_back(pctAcc, pctCur, make_pair(targetAcc, targetCur));
// Now move accumulators for the next tuple/completion
pctAcc += pctCur;
targetAcc += targetCur;
// Expect/consume separator for next tuple?
if (*arg == ':')
{
++arg;
continue;
}
// Done?
if (*arg == '\0')
{
break;
}
fprintf(stderr, "Unexpected characters in specification '%s'\n", arg);
return false;
}
// Apply to all targets
for (auto& t : vTargets)
{
t.SetDistributionRange(vOr, dType);
}
return true;
}