/* Web Polygraph http://www.web-polygraph.org/ * (C) 2003-2006 The Measurement Factory * Licensed under the Apache License, Version 2.0 */ #include "base/polygraph.h" #include "xstd/h/iomanip.h" #include "xstd/Clock.h" #include "runtime/Agent.h" #include "runtime/Connection.h" #include "runtime/Xaction.h" #include "runtime/IcpXaction.h" #include "runtime/PageInfo.h" #include "base/StatIntvlRec.h" #include "runtime/StatIntvl.h" #include "runtime/globals.h" #include "xstd/gadgets.h" #include "runtime/polyBcastChannels.h" #include "base/polyLogCats.h" int StatIntvl::TheReportCat = lgcAll; Array StatIntvl::IsActiveCat(lgcEnd); void StatIntvl::ActiveCat(int cat) { Assert(0 <= cat && cat < lgcEnd); IsActiveCat.put(true, cat); } StatIntvl::StatIntvl() { Assert(TheConnOpenChannel); theChannels << TheAgentBegChannel << TheAgentEndChannel << TheConnOpenChannel << TheConnEstChannel << TheConnCloseChannel << TheConnSslActiveChannel << TheXactBegChannel << TheXactEndChannel << TheXactErrChannel << TheXactRetrChannel << TheIcpXactBegChannel << TheIcpXactEndChannel << TheIcpXactErrChannel << ThePageEndChannel << TheWaitBegChannel << TheWaitEndChannel ; } void StatIntvl::setDuration(Time start) { const Time dur = TheClock.time() >= start ? TheClock - start : Time(0,0); for (int i = 0; i < IsActiveCat.count(); ++i) { if (IsActiveCat[i]) getRec(i).theDuration = dur; } } void StatIntvl::storeAll(OLog &ol, int tag) const { for (int i = 0; i < IsActiveCat.count(); ++i) { if (IsActiveCat[i]) { ol << bege(tag, i); getRec(i).store(ol); ol << ende; } } } void StatIntvl::noteAgentEvent(BcastChannel *ch, const Agent *a) { Assert(a); StatIntvlRec &rec = getRec(a->logCat()); if (ch == TheAgentBegChannel) { ++rec.thePopulusLvl; } else if (ch == TheAgentEndChannel) { --rec.thePopulusLvl; } else { Assert(false); } checkpoint(); } void StatIntvl::noteConnEvent(BcastChannel *ch, const Connection *conn) { Assert(conn); StatIntvlRec &rec = getRec(conn->logCat()); if (ch == TheConnOpenChannel) { ++rec.theOpenLvl; // only server-side SSL connections counted here if (conn->sslActive()) ++rec.theSslStat.connLevel(); } else if (ch == TheConnSslActiveChannel) { Should(conn->sslActive()); ++rec.theSslStat.connLevel(); } else if (ch == TheConnEstChannel) { ++rec.theEstbLvl; } else { Assert(ch == TheConnCloseChannel); if (!conn->bad()) { rec.theConnLifeTm.record((TheClock - conn->openTime()).msec()); rec.theConnUseCnt.record(conn->useCnt()); // record greater-than-1 depths only to get pipelining probability later const int depth = conn->useLevelMax(); if (depth > 1) rec.theConnPipelineDepth.record(depth); } if (conn->ioCnt()) --rec.theEstbLvl; --rec.theOpenLvl; if (conn->sslActive()) --rec.theSslStat.connLevel(); } checkpoint(); } void StatIntvl::noteXactEvent(BcastChannel *ch, const Xaction *x) { Assert(x); StatIntvlRec &rec = getRec(x->logCat()); if (ch == TheXactBegChannel) { ++rec.theXactLvl; if (x->sslConfigured()) ++rec.theSslStat.xactLevel(); } else if (ch == TheXactEndChannel) { const ObjId &oid = x->oid(); const Time repTime = x->lifeTime(); const Size repSize = x->repSize().actual(); // stats must be recorded in only one category for totals to work! if (oid.basic()) { // XXX: calculate and use "ideal" time here rec.theIdealHR.record(Time(0,0), repSize, oid.offeredHit()); rec.theRealHR.record(repTime, repSize, oid.hit()); rec.theChbR.record(repTime, repSize, oid.cachable()); if (oid.fill()) rec.theFill.record(repTime, repSize); } else if (oid.repToRedir()) rec.theRepToRedir.record(repTime, repSize); else if (oid.rediredReq()) rec.theRediredReq.record(repTime, repSize); else if (oid.imsAny()) // should we count 304s separately? rec.theIms.record(repTime, repSize); else if (oid.reload()) rec.theReload.record(repTime, repSize); else if (oid.head()) rec.theHead.record(repTime, repSize); else if (oid.post()) rec.thePost.record(repTime, repSize); else if (oid.put()) rec.thePut.record(repTime, repSize); else if (oid.aborted()) rec.theAbort.record(repTime, repSize); else { Should(false); // all categories should be accounted for } rec.theXactCnt++; --rec.theXactLvl; if (x->sslConfigured()) { --rec.theSslStat.xactLevel(); // comparison with pure HTTP misses will not be accurate // comparison with pure HTTP hits and not-hits will be accurate rec.theSslStat.doneXacts().record(repTime, repSize, oid.basic() && oid.hit()); } } else if (ch == TheWaitBegChannel) { ++rec.theWaitLvl; } else if (ch == TheWaitEndChannel) { --rec.theWaitLvl; } else if (ch == TheXactErrChannel) { rec.theXactErrCnt++; if (x && x->started()) { --rec.theXactLvl; if (x->sslConfigured()) { --rec.theSslStat.xactLevel(); rec.theSslStat.recordXactError(); } } } else if (ch == TheXactRetrChannel) { rec.theXactRetrCnt++; if (x && x->started()) { --rec.theXactLvl; if (x->sslConfigured()) --rec.theSslStat.xactLevel(); } } else { Assert(false); } checkpoint(); } void StatIntvl::noteIcpXactEvent(BcastChannel *ch, const IcpXaction *x) { Assert(x); StatIntvlRec &rec = getRec(x->logCat()); if (ch == TheIcpXactEndChannel) { if (x->timedout()) rec.theIcpStat.recordTimeout(); else rec.theIcpStat.record(x->lifeTime(), x->repSize(), x->hit()); } checkpoint(); } void StatIntvl::notePageEvent(BcastChannel *ch, const PageInfo *p) { Assert(p); StatIntvlRec &rec = getRec(lgcCltSide); if (ch == ThePageEndChannel) rec.thePage.record(p->lifeTime, p->size); checkpoint(); } bool StatIntvl::checkpoint() { return false; }