void spring_time::sleep(bool forceThreadSleep) { if (forceThreadSleep) { spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); return; } // for very short time intervals use a yielding loop (yield is ~5x more accurate than sleep(), check the UnitTest) if (toMicroSecsi() < (avgThreadSleepTimeMicroSecs + avgThreadYieldTimeMicroSecs * 5)) { const spring_time s = gettime(); while ((gettime() - s) < *this) thread_yield(); return; } // expected wakeup time const spring_time t0 = gettime() + *this; spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); const spring_time t1 = gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadSleepTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadSleepTimeMicroSecs.store(newAvg); } }
void CTimeProfiler::AddTime(const std::string& name, const spring_time time, const bool showGraph) { auto pi = profile.find(name); if (pi != profile.end()) { // profile already exists //FIXME use atomic ints auto& p = pi->second; p.total += time; p.current += time; p.frames[currentPosition] += time; if (p.maxLag < time.toMilliSecsf()) { p.maxLag = time.toMilliSecsf(); p.newLagPeak = true; } } else { boost::unique_lock<boost::mutex> ulk(m, boost::defer_lock); while (!ulk.try_lock()) {} // create a new profile auto& p = profile[name]; p.total = time; p.current = time; p.maxLag = time.toMilliSecsf(); p.percent = 0; memset(p.frames, 0, TimeRecord::frames_size * sizeof(unsigned)); static UnsyncedRNG rand; rand.Seed(spring_tomsecs(spring_gettime())); p.color.x = rand.RandFloat(); p.color.y = rand.RandFloat(); p.color.z = rand.RandFloat(); p.showGraph = showGraph; } }
void spring_time::sleep() { // for very short time intervals use a yielding loop (yield is ~5x more accurate than sleep(), check the UnitTest) if (toMilliSecsf() < (avgThreadSleepTimeMilliSecs + avgThreadYieldTimeMilliSecs * 5.0f)) { const spring_time s = gettime(); while ((gettime() - s) < *this) thread_yield(); return; } // expected wakeup time const spring_time t0 = gettime() + *this; #if defined(SPRINGTIME_USING_STD_SLEEP) this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); #else boost::this_thread::sleep(boost::posix_time::microseconds(std::ceil(toNanoSecsf() * 1e-3))); #endif const spring_time t1 = gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { boost::mutex::scoped_lock lock(sleepTimeMutex); avgThreadSleepTimeMilliSecs = mix(avgThreadSleepTimeMilliSecs, dt.toMilliSecsf(), 0.1f); } }
static void thread_yield() { const spring_time t0 = spring_time::gettime(); this_thread::yield(); const spring_time t1 = spring_time::gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { boost::mutex::scoped_lock lock(yieldTimeMutex); avgThreadYieldTimeMilliSecs = mix(avgThreadYieldTimeMilliSecs, dt.toMilliSecsf(), 0.1f); } }
static void thread_yield() { const spring_time t0 = spring_time::gettime(); this_thread::yield(); const spring_time t1 = spring_time::gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadYieldTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadYieldTimeMicroSecs.store(newAvg); } }
std::int64_t CPathManager::Finalize() { const spring_time t0 = spring_gettime(); { // maxResPF only runs on the main thread, so can be unsafe maxResPF = pfMemPool.alloc<CPathFinder>(false); medResPE = peMemPool.alloc<CPathEstimator>(maxResPF, MEDRES_PE_BLOCKSIZE, "pe", mapInfo->map.name); lowResPE = peMemPool.alloc<CPathEstimator>(medResPE, LOWRES_PE_BLOCKSIZE, "pe2", mapInfo->map.name); // make cached path data checksum part of synced state // so that when any client has a corrupted / incorrect // cache it desyncs from the start, not minutes later { SyncedUint tmp(GetPathCheckSum()); } } const spring_time dt = spring_gettime() - t0; return (dt.toMilliSecsi()); }
static void DrawTimeSlice(std::deque<TimeSlice>& frames, const spring_time curTime, const spring_time maxHist, const float drawArea[4]) { // remove old entries while (!frames.empty() && (curTime - frames.front().second) > maxHist) { frames.pop_front(); } const float y1 = drawArea[1]; const float y2 = drawArea[3]; // render CVertexArray* va = GetVertexArray(); va->Initialize(); for (TimeSlice& ts: frames) { float x1 = (ts.first % maxHist).toSecsf() / maxHist.toSecsf(); float x2 = (ts.second % maxHist).toSecsf() / maxHist.toSecsf(); x2 = std::max(x1 + globalRendering->pixelX, x2); x1 = drawArea[0] + x1 * (drawArea[2] - drawArea[0]); x2 = drawArea[0] + x2 * (drawArea[2] - drawArea[0]); va->AddVertex0(x1, y1, 0.0f); va->AddVertex0(x1, y2, 0.0f); va->AddVertex0(x2, y2, 0.0f); va->AddVertex0(x2, y1, 0.0f); const float mx1 = x1 + 3 * globalRendering->pixelX; const float mx2 = x2 - 3 * globalRendering->pixelX; if (mx1 < mx2) { va->AddVertex0(mx1, y1 + 3 * globalRendering->pixelX, 0.0f); va->AddVertex0(mx1, y2 - 3 * globalRendering->pixelX, 0.0f); va->AddVertex0(mx2, y2 - 3 * globalRendering->pixelX, 0.0f); va->AddVertex0(mx2, y1 + 3 * globalRendering->pixelX, 0.0f); } } va->DrawArray0(GL_QUADS); }
void SmoothController::ScreenEdgeMove(float3 move) { if (flipped) { move.x = -move.x; move.y = -move.y; } move *= math::sqrt(move.z) * 200.0f; const float3 thisMove(move.x * pixelSize * 2.0f * scrollSpeed, 0.0f, -move.y * pixelSize * 2.0f * scrollSpeed); static spring_time lastScreenMove = spring_gettime(); const spring_time timeDiff = spring_gettime() - lastScreenMove; lastScreenMove = spring_gettime(); if (thisMove.x != 0 || thisMove.z != 0) { // user want to move with mouse on screen edge lastSource = ScreenEdge; Move(thisMove, timeDiff.toMilliSecsf()); } else if (lastSource == ScreenEdge) { // last move order was given by screen edge, so call Move() to break Move(thisMove, timeDiff.toMilliSecsf()); } }
void CTimeProfiler::Update() { //FIXME non-locking threadsafe boost::unique_lock<boost::mutex> ulk(m, boost::defer_lock); while (!ulk.try_lock()) {} ++currentPosition; currentPosition &= TimeRecord::frames_size-1; for (auto& pi: profile) { pi.second.frames[currentPosition] = spring_notime; } const spring_time curTime = spring_gettime(); const float timeDiff = spring_diffmsecs(curTime, lastBigUpdate); if (timeDiff > 500.0f) // twice every second { for (auto& pi: profile) { auto& p = pi.second; p.percent = spring_tomsecs(p.current) / timeDiff; p.current = spring_notime; p.newLagPeak = false; p.newPeak = false; if(p.percent > p.peak) { p.peak = p.percent; p.newPeak = true; } } lastBigUpdate = curTime; } if (curTime.toSecsi() % 6 == 0) { for (auto& pi: profile) { auto& p = pi.second; p.maxLag *= 0.5f; } } }
void linux_signal::wait_for(spring_time t) { int m; // cur gen const int g = gen.load(); // our gen sleepers++; struct timespec linux_t; linux_t.tv_sec = 0; linux_t.tv_nsec = t.toNanoSecsi(); const spring_time endTimer = spring_now() + t; while (((g - (m = mtx)) >= 0) && (spring_now() < endTimer)) { syscall(SYS_futex, &mtx, FUTEX_WAIT_PRIVATE, m, &linux_t, NULL, 0); } sleepers--; }