void SchedulerTimer::init(MemoryMgrPrimitive * memory) { SchedulerTimer tmp; // Get vtbl pointer right memcpy(this, &tmp, sizeof(tmp)); anchor = 0; now = 0; when=SysTime(-1); uval ptr; memory->alloc(ptr, TABLE_SIZE*sizeof(AutoListHead), PAGE_SIZE); table = (AutoListHead*)ptr; uval i = 0; // We need to legitimately construct this object, and then make // copies of it. This ensures that vtable pointers are set right // (we don't "construct" array elements). AutoListHead alh; alh.init(); memcpy(&immediate, &alh, sizeof(AutoListHead)); immediate.init(); for (; i<TABLE_SIZE; ++i) { memcpy(&table[i],&alh, sizeof(AutoListHead)); table[i].init(); } }
/** Method that is called after execution of the task. */ void End() { DBG_ASSERT(!end_called_); DBG_ASSERT(start_called_); end_called_ = true; start_called_ = false; total_cputime_ += CpuTime() - start_cputime_; total_systime_ += SysTime() - start_systime_; total_walltime_ += WallclockTime() - start_walltime_; }
/** Method that is called before execution of the task. */ void Start() { DBG_ASSERT(end_called_); DBG_ASSERT(!start_called_); end_called_ = false; start_called_ = true; start_cputime_ = CpuTime(); start_systime_ = SysTime(); start_walltime_ = WallclockTime(); }
/** Method that is called after execution of the task for which * timing might have been started. This only updates the timing * if the timing has indeed been conducted. This is useful to * stop timing after catching exceptions. */ void EndIfStarted() { if (start_called_) { end_called_ = true; start_called_ = false; total_cputime_ += CpuTime() - start_cputime_; total_systime_ += SysTime() - start_systime_; total_walltime_ += WallclockTime() - start_walltime_; } DBG_ASSERT(end_called_); }
/* * if timer ever uses storage to do a more efficient job of managing * the set of timer events, then the PostFork init will differ from * the init above */ /* virtual */ void SchedulerTimer::initPostFork(ForkData *fd) { AutoListHead alh; alh.init(); memcpy(&immediate, &alh, sizeof(AutoListHead)); immediate.init(); when = SysTime(-1); anchor = NULL; table = fd->table; for (uval i = 0; i < TABLE_SIZE; i++) { table[i].init(); } }
void Clock::MeasureFps() { cnt++; if(cnt>timing) { double current = SysTime(); double elapsed = current - last; // reset cnt=0; last = current; fps = timing/elapsed; } }
void CgFXPassChunk::updateStateUniforms(DrawEnv *pEnv) { CgFXMaterial *pMat = _sfMaterial.getValue(); OSG_ASSERT(pMat != NULL); CGeffect pEffect = pMat->getEffect (); UInt32 uiStateVars = pMat->getStateVariables(); const std::string *vStateVarNames = pMat->getStateVarNames (); UInt32 uiMask = 0x0001; OSG_ASSERT(pEffect != NULL); Matrix mObj2World = pEnv->getObjectToWorld(); std::string szTmp; for(UInt32 i = 0; i < CgFXMaterial::NumStateVars; ++i) { if(uiStateVars == 0x0000) break; switch(uiStateVars & uiMask) { case CgFXMaterial::CgProjectionMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgProjection].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); cgGLSetMatrixParameterfc( pMatrixParam, pEnv->getCameraFullProjection().getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgModelViewProjectionMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgModelViewProjection].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); Matrix mWorld2Scrn = pEnv->getWorldToScreen(); mWorld2Scrn.mult(mObj2World); cgGLSetMatrixParameterfc(pMatrixParam, mWorld2Scrn.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; // ------------- // Model | World // ------------- case CgFXMaterial::CgModelMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgModel].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); cgGLSetMatrixParameterfc(pMatrixParam, mObj2World.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgModelIMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgModelI].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); Matrix mModelI = mObj2World; mModelI.invert(); cgGLSetMatrixParameterfc(pMatrixParam, mModelI.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgModelITMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgModelIT].c_str()); OSG_ASSERT(pMatrixParam != NULL); Matrix mModelIT = mObj2World; mModelIT.invert (); mModelIT.transpose(); cgGLSetMatrixParameterfc(pMatrixParam, mModelIT.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; // --------------------- // ModelView | WorldView // --------------------- case CgFXMaterial::CgModelViewMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[CgFXMaterial::CgModelView].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); Matrix mCameraViewing = pEnv->getCameraViewing(); mCameraViewing.mult(mObj2World); cgGLSetMatrixParameterfc(pMatrixParam, mCameraViewing.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgModelViewIMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[CgFXMaterial::CgModelViewI].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); Matrix mCameraViewing = pEnv->getCameraViewing(); mCameraViewing.mult(mObj2World); mCameraViewing.invert(); cgGLSetMatrixParameterfc(pMatrixParam, mCameraViewing.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgModelViewITMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[CgFXMaterial::CgModelViewIT].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); Matrix mCameraViewing = pEnv->getCameraViewing(); mCameraViewing.mult (mObj2World); mCameraViewing.invert ( ); mCameraViewing.transpose( ); cgGLSetMatrixParameterfc(pMatrixParam, mCameraViewing.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; // ------------- // View // ------------- case CgFXMaterial::CgViewMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgView].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); cgGLSetMatrixParameterfc(pMatrixParam, pEnv->getCameraViewing().getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgViewIMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgViewI].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); OSG::Matrix mCameraViewing = pEnv->getCameraViewing(); mCameraViewing.invert(); cgGLSetMatrixParameterfc(pMatrixParam, mCameraViewing.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgViewITMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgViewIT].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); OSG::Matrix mCameraViewing = pEnv->getCameraViewing(); mCameraViewing.invert (); mCameraViewing.transpose(); cgGLSetMatrixParameterfc(pMatrixParam, mCameraViewing.getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgViewProjectionMask: { CGparameter pMatrixParam = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgViewProjection].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pMatrixParam != NULL); cgGLSetMatrixParameterfc(pMatrixParam, pEnv->getWorldToScreen().getValues()); CgFXMaterial::checkForCgError("cgGLSetMatrixParameterfc", NULL); } break; case CgFXMaterial::CgTimeMask: { CGparameter pTime = cgGetNamedEffectParameter( pEffect, vStateVarNames[ CgFXMaterial::CgTime].c_str()); CgFXMaterial::checkForCgError("cgGetNamedEffectParameter", NULL); OSG_ASSERT(pTime != NULL); static const UInt16 MaxLeftDecDigits(4); //getSystemTime() returns a time value as a 64-bit floating //point number. But the time value taken by Cg is a 32-bit //float. This can cause a problem with precision when //getSystemTime() returns large values, that truncate when cast //to a 32-bit float. // //To deal with this, we are removing the most significant //decimal digits left of the decimal points after the MaxLeftDecDigits //one Time SysTime(OSG::getSystemTime()); Time Base10Shift(osgPow<Time>(10,MaxLeftDecDigits)); Time TruncValue(SysTime - (floor(SysTime / Base10Shift) * Base10Shift)); cgSetParameter1f(pTime, static_cast<Real32>(TruncValue)); } break; default: break; }; uiStateVars &= ~uiMask; uiMask = uiMask << 1; } }
int getSysTime(float modelBaseRate){ if (m_systime == 0) { m_systime = SysTime (modelBaseRate) ; //after timer has been init, set to 1 } return m_systime ; }
void SchedulerTimer::timerInterrupt(SoftIntr::IntrType) { // use when as estimate of time unless its cheap to read // the clock // FIXME: This usermodeClock trick assumes that interrupts won't be // delivered earlier than expected, an assumption that is // violated when a dispatcher is migrated from one physical // processor to another. An early interrupt will cause us to // invoke event handlers before their expected times. To fix // this problem, we should pass the current time up to the // dispatcher when we generate a soft timer interrupt for it. SysTime old = when; SysTime start = old; AutoListHead runList; runList.init(); now = usermodeClock?getClock():when; TimerEvent* cur; if (unlikely(now < when)) { if (when == SysTime(-1)) { now = _TIMER_REQUEST(when, TimerEvent::reset); } else { now = _TIMER_REQUEST(when,TimerEvent::absolute); } } while (now > when) { cur = anchor; // Run the current timer anchor = NULL; if (cur) { cur->lockedDetach(); // tassertWrn(old <= cur->when, "stale event: %lx %lx %lx\n", // uval(old), uval(cur->when), uval(now)); runList.prepend(cur); } cur = (TimerEvent*)immediate.next(); // Scan immediate timer list, looking for expired timers, // first timer to go off next. while (cur) { TimerEvent *te = cur; cur = (TimerEvent*)cur->next(); tassertMsg(bucketEnd(now)>=te->when, "Bad event on immediate list: %lx %lx %p\n", uval(now), uval(te->when), te); if (te->when <= now) { te->lockedDetach(); tassertWrn(old <= te->when, "stale event3: %lx %lx %lx\n", uval(old), uval(te->when), uval(now)); runList.prepend(te); } else if (!anchor || te->when <= anchor->when) { anchor = te; when = te->when; } } // Move all events for buckets containing "start" to "now" // to immediate list migrate(start, now, runList); if (!anchor) { // No "anchor" timer to go off next, look for the next bucket // with timers. // we start in current slot, then increment SysTime nextSlot = bucketStart(now + BUCKET_TICKS); while (timeIndex(old) != timeIndex(nextSlot) && !table[timeIndex(nextSlot)].next()) { nextSlot += BUCKET_TICKS; } if (timeIndex(now) == timeIndex(nextSlot) && !table[timeIndex(nextSlot)].next()) { when = SysTime(-1); } else { when = nextSlot; } } #if 0 if (when==SysTime(-1)) { SchedulerTimer *st = &DISPATCHER->timer; for (uval i = 0; i<TABLE_SIZE; ++i) { TimerEvent *t = (TimerEvent*)st->table[i].next(); tassertMsg(t==NULL, "Existing event, no timer: %lx %p %p %p %p\n", i,t,st,DISPATCHER,this); } } { SchedulerTimer *st = &DISPATCHER->timer; for (uval i = 0; i<TABLE_SIZE; ++i) { TimerEvent *t = (TimerEvent*)st->table[i].next(); while (t) { tassertMsg(timeIndex(t->when) != timeIndex(now) || t->when > bucketEnd(now), "event not in immediate: %p %lx %lx %lx\n",t, uval(now), uval(t->when), uval(when)); tassertMsg(t->when > now, "stale event in table %p\n", t); t = (TimerEvent*)t->next(); } } } #endif // adjust timer only if it has changed if (when != old) { if (when == SysTime(-1)) { now = _TIMER_REQUEST(when, TimerEvent::reset); } else { now = _TIMER_REQUEST(when,TimerEvent::absolute); } } } // Run expired timers We do this after all of the processing abov, // rather than as we encounter these events because handleEvent() // may lead to SchedulerTimer::disabledScheduleEvent, and we don't // want that code to run while the timer object's state is in the // midst of the computations above -- we want that code to run on // a clean slate. Only now can we run these callbacks while // ensuring that SchedulerTimer is fully cleaned up. cur = (TimerEvent*)runList.next(); while (cur) { TimerEvent *te = (TimerEvent*)cur; cur = (TimerEvent*)cur->next(); te->lockedDetach(); te->handleEvent(); } // err_printf("next timer: %p %lx\n", DISPATCHER, uval(when)); }
/* * * runs disabled to protect timer event structures. * also, _TIMER_REQUEST must only be called disabled */ SysTime SchedulerTimer::disabledScheduleEvent(TimerEvent* timerEvent, SysTime whenTime, TimerEvent::Kind kind) { #if 0 // kludge which can be used to catch unpinned timer events in the // kernel passertMsg((uval)timerEvent >= 0xc000000000000000ul || (uval)timerEvent < 0x8000000000000000ul, "opps\n"); #endif AutoListNode *list = NULL; SysTime old = when; switch (kind) { default: return 0; case TimerEvent::queryTicksPerSecond: return kernelInfoLocal.systemGlobal.ticksPerSecond; case TimerEvent::queryNow: if (usermodeClock) { now = getClock(); } else { now = _TIMER_REQUEST(0, TimerEvent::queryNow); } break; case TimerEvent::reset: list = timerEvent->head(); if (!list) { break; } timerEvent->lockedDetach(); if (likely(timerEvent != anchor && // timerEvent bucket is non-empty !(when == bucketStart(timerEvent->when) && !list->next()))) { break; } if (timerEvent == anchor) { anchor = NULL; list = immediate.next(); when = SysTime(-1); while (list) { TimerEvent* te = (TimerEvent*)list; list = list->next(); if (!anchor || anchor->when > te->when) { anchor = te; when = anchor->when; } } } if (!anchor) { SysTime currSlot = bucketStart(timerEvent->when + BUCKET_TICKS); while (timeIndex(currSlot)!= timeIndex(timerEvent->when) && !table[timeIndex(currSlot)].next()) { currSlot += BUCKET_TICKS; } if (timeIndex(currSlot) == timeIndex(timerEvent->when)) { when = SysTime(-1); } else { when = currSlot; } } if ( old != when ) { if (when == SysTime(-1)) { now = _TIMER_REQUEST(when, TimerEvent::reset); } else { now = _TIMER_REQUEST(when, TimerEvent::absolute); } } tassertMsg(when == SysTime(-1) || (!anchor && (when == bucketStart(when))) || (anchor && when == anchor->when), "bad timer setting\n"); break; case TimerEvent::relative: tassertMsg(timerEvent->head() == NULL, "event on list\n"); if (unlikely(whenTime==0)) { now = _TIMER_REQUEST(0, TimerEvent::queryNow); timerEvent->when = now; timerEvent->lockedDetach(); timerEvent->handleEvent(); break; } if (!usermodeClock) { // N.B. this call changes the event time only if the // new event is sooner than the current event if any now = _TIMER_REQUEST(whenTime, TimerEvent::relative); whenTime += now; } else { // we can read the clock cheaply now = getClock(); whenTime+=now; } // fall through to absolute case case TimerEvent::absolute: #if 0 //code to catch someone setting small timeouts if ( whenTime-now<marcLimit) { // don't complain about what is most likely the // dispatcher two minute warning // if (!(DREFGOBJ(TheProcessRef)->getPID() == 0 && // whenTime-now == 20000)) { err_printf("small whenTime %lld pid %ld\n", whenTime-now, DREFGOBJ(TheProcessRef)->getPID()); } #endif /* #if 0 */ tassertMsg(timerEvent->head() == NULL, "event on list\n"); if (unlikely(whenTime <= now)) { now = _TIMER_REQUEST(0, TimerEvent::queryNow); timerEvent->when = now; timerEvent->lockedDetach(); timerEvent->handleEvent(); break; } timerEvent->when = whenTime; if (timerEvent->when <= bucketEnd(now)) { // Event is in immediate window if (!anchor || anchor->when > timerEvent->when) { // Event is next to go off --- requires timer adjustment tassertMsg(!anchor || timerEvent->when <= bucketEnd(anchor->when), "event not in immediate bucket\n"); immediate.append(timerEvent); anchor = timerEvent; when = whenTime; // We may have already set the timer above if (usermodeClock) { if (old != when) { now = _TIMER_REQUEST(when, TimerEvent::absolute); } } tassertMsg(when == SysTime(-1) || (!anchor && (when == bucketStart(when))) || (anchor && when == anchor->when), "bad timer setting\n"); break; } tassertMsg(!anchor || timerEvent->when <= bucketEnd(now), "event not in immediate bucket\n"); immediate.prepend(timerEvent); } else { // Dump event into the right bucket table[timeIndex(timerEvent->when)].append(timerEvent); if (timerEvent->when < when) { // Set timer for bucket of this event when = bucketStart(timerEvent->when); anchor = NULL; if (old != when) { now = _TIMER_REQUEST(when, TimerEvent::absolute); } tassertMsg(when == SysTime(-1) || (!anchor && (when == bucketStart(when))) || (anchor && when == anchor->when), "bad timer setting\n"); } } tassertMsg(when <= timerEvent->when, "No timer before scheduled event: %p %p\n", this, timerEvent); tassertMsg(when == SysTime(-1) || (!anchor && (when == bucketStart(when))) || (anchor && when == anchor->when), "bad timer setting\n"); } #if 0 { SchedulerTimer *st = this; for (uval i = 0; i<TABLE_SIZE; ++i) { TimerEvent *t = (TimerEvent*)st->table[i].next(); while (t) { tassertMsg(timeIndex(t->when) != timeIndex(now) || t->when > bucketEnd(now), "event not in immediate: %p %lx %lx %lx %lx\n", timerEvent, uval(now), uval(now), uval(t->when), uval(when)); tassertMsg(t->when > now, "stale event in table %p\n", t); t = (TimerEvent*)t->next(); } } } #endif return now; }
SysStatus ProcessVPList::detachDispatcher(CPUDomainAnnex *cda, DispatcherID dspid, HATRef hatRef) { SysStatus rc; VPInfo *vpInfo; ProcessAnnex *pa; uval64 ipcRetryIDs; tassertMsg(cda->getPP() == Scheduler::GetVP(), "CDA not on this pp.\n"); RDNum rd; VPNum vp; SysTypes::UNPACK_DSPID(dspid, rd, vp); if (requests.enter() < 0) { return _SERROR(2642, 0, ESRCH); // process being destroyed } rc = findProcessAnnex(rd, vp, vpInfo, pa); if (_FAILURE(rc)) { requests.leave(); return rc; } if (!pa->isAttached(cda)) { requests.leave(); return _SERROR(2643, 0, EINVAL); } vpInfo->lock.acquire(); disableHardwareInterrupts(); if (pa->reservedThread != NULL) { /* * FIXME: For now, don't try to detach a dispatcher that is currently * disabled. We have to do better in the long run. */ enableHardwareInterrupts(); rc = _SERROR(2312, 0, EAGAIN); goto CleanupAndReturn; } pa->detach(); exceptionLocal.ipcTargetTable.remove(pa); if (KernelTimer::TimerRequestTime(pa) != SysTime(-1)) { /* * PA has a timeout request registered. Rather than try to reproduce * it on the new processor, we simply generate a TIMER_EVENT soft * interrupt so that the dispatcher can sort things out for itself. */ (void) pa->dispatcher->interrupts.fetchAndSet(SoftIntr::TIMER_EVENT); } exceptionLocal.kernelTimer.remove(pa); ipcRetryIDs = IPCRetryManager::GetIPCRetryIDs(pa); if (ipcRetryIDs != 0) { /* * PA has IPCs waiting to be retried. Simply generate notifications * for all of them, to be delivered when the dispatcher runs. */ pa->dispatcher->ipcRetry |= ipcRetryIDs; (void) pa->dispatcher->interrupts. fetchAndSet(SoftIntr::IPC_RETRY_NOTIFY); } exceptionLocal.ipcRetryManager.remove(pa); enableHardwareInterrupts(); vpInfo->dspCounter--; if (vpInfo->dspCounter > 0) { rc = 0; goto CleanupAndReturn; } /* * This VP's last dispatcher has now been detached, so detach the VP. * Switch to the canonical kernel address space, in case we're currently * "borrowing" the address space we're about to unmap. */ ((HATKernel*)(DREFGOBJK(TheKernelHATRef)))->switchToKernelAddressSpace(); rc = DREF(hatRef)->detachVP(vp); tassertMsg(_SUCCESS(rc), "hat->detachVP() failed.\n"); vpInfo->pp = ProcessAnnex::NO_PHYS_PROC; // VP now ready for re-attachment rc = 0; CleanupAndReturn: vpInfo->lock.release(); requests.leave(); return rc; }