/* 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 "base/UniqId.h" #include "runtime/StatPhase.h" #include "runtime/StatPhaseMgr.h" #include "runtime/StatPhaseSync.h" class StatPhaseGroup { public: StatPhaseGroup(const UniqId &aGroup): theGroup(aGroup), thePhaseSyncPos(-1) {} const UniqId &group() const { return theGroup; } int phaseSyncPos() const { return thePhaseSyncPos; } void phaseSyncPos(int aPos) { thePhaseSyncPos = aPos; } protected: UniqId theGroup; int thePhaseSyncPos; }; StatPhaseSync TheStatPhaseSync; // XXX: we need to grow this map on-demand basis! StatPhaseSync::StatPhaseSync(): theIndex(37), theCount(0), thePhaseSyncPosMin(-1) { } StatPhaseSync::~StatPhaseSync() { while (theIndex.count()) delete theIndex.pop(); } int StatPhaseSync::phaseSyncPos() const { return Min(thePhaseSyncPosMin, TheStatPhaseMgr.phaseSyncPos()); } int StatPhaseSync::waitGroupCount() const { const int ourPos = TheStatPhaseMgr.phaseSyncPos(); int cnt = 0; for (int i = 0; i < capacity(); ++i) { if (StatPhaseGroup *r = theIndex[i]) { if (r->phaseSyncPos() < ourPos) cnt++; } } return cnt; } void StatPhaseSync::notePhaseSync(const UniqId &group, int pos) { int idx = -1; if (!find(group, idx)) { addAt(idx, group); Assert(pos >= 0); thePhaseSyncPosMin = -1; // will force sync check below } StatPhaseGroup *grp = theIndex[idx]; const int oldPos = grp->phaseSyncPos(); // ignore stale information if (pos <= oldPos) return; grp->phaseSyncPos(pos); if (thePhaseSyncPosMin < pos) { thePhaseSyncPosMin = -1; bool inited = false; for (int i = 0; i < capacity(); ++i) { if (StatPhaseGroup *r = theIndex[i]) { if (!inited || r->phaseSyncPos() < thePhaseSyncPosMin) { thePhaseSyncPosMin = r->phaseSyncPos(); inited = true; } } } } if (TheStatPhaseMgr->unlockToStop() && TheStatPhaseMgr.phaseSyncPos() <= thePhaseSyncPosMin) TheStatPhaseMgr->unlock(); } bool StatPhaseSync::find(const UniqId &group, int &idx) const { if (!capacity()) return false; // start with a hash and then try linear search idx = group.hash() % capacity(); for (int i = capacity(); i; --i) { bool res = false; if (endSearch(group, idx, res)) return res; idx++; idx %= capacity(); } Assert(false); // no empty slots left! return false; } StatPhaseGroup *StatPhaseSync::addAt(int idx, const UniqId &group) { Assert(group); Assert(!theIndex[idx]); theIndex.put(new StatPhaseGroup(group), idx); theCount++; return theIndex[idx]; } // returns true if there is no reason to search further (match or empty) bool StatPhaseSync::endSearch(const UniqId &group, int idx, bool &res) const { if (StatPhaseGroup *h = theIndex[idx]) { if (h->group() == group) return res = true; return res = false; } // found empty slot res = false; return true; }