/* 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 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 &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; }