/* Web Polygraph http://www.web-polygraph.org/
* (C) 2003-2006 The Measurement Factory
* Licensed under the Apache License, Version 2.0 */
#include "pgl/pgl.h"
#include "xstd/h/math.h"
#include "xstd/h/iostream.h"
#include "xstd/h/sstream.h"
#include "xstd/String.h"
#include "xstd/gadgets.h"
#include "pgl/PglRec.h"
#include "pgl/PglIntSym.h"
#include "pgl/PglNetAddrRange.h"
#include "pgl/PglNetAddrRangeSym.h"
#include "pgl/PglNetAddrSym.h"
#include "pgl/PglClonerSym.h"
#include "pgl/PglArraySym.h"
#include "pgl/VerFourAsSym.h"
#include "pgl/BenchSym.h"
#include "pgl/BenchSideSym.h"
const String VerFourAsSym::TheType = "VerFourAs";
static String strAgents_per_addr = "agents_per_addr";
VerFourAsSym::VerFourAsSym(const String &aType, PglRec *aRec): AddrSchemeSym(aType, aRec) {
theRec->bAdd(IntSym::TheType, strAgents_per_addr, 0);
}
bool VerFourAsSym::agentsPerAddr(int &apa) const {
return getInt(strAgents_per_addr, apa);
}
String VerFourAsSym::addresses(const BenchSideSym *side, ArraySym *&addrs) const {
if (!side)
return "bench side is not specified";
if (SynSym *ams = side->addrMaskSym()) {
cerr << ams->loc() << "warning: addressing schemes in fourth"
<< " generation workloads use addr_space instead of addr_mask;"
<< " consider removing depricated addr_mask from your new"
<< " workloads" << endl;
}
const ArraySym *addrSpace = side->addrSpace();
if (!addrSpace)
return "addr_space not set";
Assert(side->bench());
double reqRate, hostLoad, agentLoad;
int addrLoad;
if (!side->bench()->peakReqRate(reqRate) ||
!side->maxHostLoad(hostLoad) ||
!side->maxAgentLoad(agentLoad) || agentLoad <= 0 ||
!this->agentsPerAddr(addrLoad) || addrLoad <= 0)
return "peak_req_rate, max_host_load, max_agent_load or agents_per_addr not set";
const int maxAgentsPerHost = (int)xceil(hostLoad, agentLoad);
const int maxAddrPerHost = (int)xceil(maxAgentsPerHost, addrLoad);
// find the number of agents
const int hostCnt = (int)xceil(reqRate, hostLoad);
const int agentCnt = // divisible by addrLoad on each host
singleDiv(hostCnt*addrLoad, doubleDiv(hostCnt, reqRate, agentLoad));
if (agentCnt > addrLoad * maxAddrPerHost * hostCnt)
return "too many agents?";
if (agentCnt > addrSpace->count())
return "too small address space";
return distributeAddrs(addrs, addrSpace, hostCnt, agentCnt, addrLoad);
}
String VerFourAsSym::distributeAddrs(ArraySym *&addrs, const ArraySym *addrSpace, int hostCnt, int agentCnt, int addrLoad) const {
const int agentPerHost = agentCnt / hostCnt;
int minSubnet;
if (const String err = this->minSubnet(agentPerHost/addrLoad, minSubnet))
return err;
Array<PglNetAddrRange*> ranges;
int ipCount = 0;
const int spaceSize = addrSpace->count();
int maxSubnet = minSubnet;
for (int h = 0, spaceIdx = 0; h < hostCnt && spaceIdx < spaceSize; ++h) {
// one subnet, one host
const NetAddrSym *lastAddr = 0;
for (int a = 0; a < agentPerHost/addrLoad && spaceIdx < spaceSize; ++a) { // agents
// one address per addrLoad agents
lastAddr = &(const NetAddrSym&)addrSpace->item(spaceIdx++)->cast(NetAddrSym::TheType);
const int thisSubnet = addAddr(ranges, *lastAddr, minSubnet);
maxSubnet = Min(thisSubnet, maxSubnet); // "/24" <= "/16"
ipCount++;
}
Assert(lastAddr);
if (const String err = skipSubnet(lastAddr->val(), maxSubnet, addrSpace, spaceIdx))
return err;
}
if (ipCount != agentCnt/addrLoad)
return "addressing scheme cannot use provided addr_space";
// merge ranges if possible
bool merged = true;
do {
merged = false;
for (int left = 0, right = 1; !merged && right < ranges.count(); ++right) {
PglNetAddrRange *&r = ranges[right];
if (!r) // deleted by earlier merges
continue;
if (ranges[left] && ranges[left]->canMerge(*r)) {
ranges[left]->merge(*r);
delete r;
r = 0;
merged = true;
} else {
left = right;
}
}
} while (merged);
// convert an array of ranges into ArraySym
ArraySym *ips = new ArraySym(NetAddrSym::TheType);
{for (int i = 0; i < ranges.count(); ++i) {
if (!ranges[i])
continue;
NetAddrRangeSym rs;
rs.range(ranges[i]);
ips->add(rs);
}}
if (addrLoad > 1) {
// addrLoad agents for each address (clone ips addrLoad times)
ArraySym *res = new ArraySym(NetAddrSym::TheType);
res->add(ClonerSym(*ips, addrLoad));
delete ips;
addrs = res;
} else {
addrs = ips;
}
return String();
}
// skips address space that is in the [beg, end] subnet
String VerFourAsSym::skipSubnet(const NetAddr &lastAddr, int subnet, const ArraySym *addrSpace, int &spaceIdx) const {
const int spaceSize = addrSpace->count();
Assert(spaceIdx < spaceSize);
for (; spaceIdx < spaceSize; ++spaceIdx) {
const NetAddrSym *nas = &(const NetAddrSym&)addrSpace->item(spaceIdx)->cast(NetAddrSym::TheType);
if (!sameSubnet(lastAddr, nas->val(), subnet))
break;
}
return String();
}
// checks whether addr belongs to the [beg, end] subnet
bool VerFourAsSym::sameSubnet(const NetAddr &addr1, const NetAddr &addr2, int subnet) const {
return addr1.addrN().sameSubnet(addr2.addrN(), subnet);
}
int VerFourAsSym::addAddr(Array<PglNetAddrRange*> &ranges, const NetAddrSym &addr, int subnet) const {
NetAddrSym *clone = (NetAddrSym*)addr.clone();
int explicitSubnet = -1;
if (!clone->subnet(explicitSubnet))
clone->setSubnet(subnet);
else
if (explicitSubnet <= subnet) // XXX: this logic is not IPv6-aware
subnet = explicitSubnet;
else {
// Newer FreeBSD versions require (/32, /128) nmasks for aliases.
// Warn, but do not quit.
const int currentHash = explicitSubnet ^ subnet;
static int warnLessHash = ~currentHash; // initialized once
if (currentHash != warnLessHash) {
warnLessHash = currentHash;
clog << addr.loc() << "warning: the explicit subnet of the " <<
addr << " address (/" << explicitSubnet << ") is 'smaller' " <<
"than minimal subnet required to accomodate all agent " <<
"addresses on one host (/" << subnet << "). Whether this " <<
"is OK depends on your environment." << endl;
}
}
PglNetAddrRange r;
ostringstream buf; // XXX: expensive mallocs
clone->printUnquoted(buf);
buf << ends;
Assert(r.parse(buf.str().c_str()));
streamFreeze(buf, false);
delete clone;
// check if can merge r with last range, add new range if failed
if (!ranges.count() || !ranges.last()->canMerge(r))
ranges.append(new PglNetAddrRange);
Assert(ranges.count());
ranges.last()->merge(r);
return subnet;
}
syntax highlighted by Code2HTML, v. 0.9.1