/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include <StdAfx.h> #include "ServerThrottle.h" #include "TimeValue.h" #include "ISystem.h" #include "ITimer.h" #include "IConsole.h" #if defined(WIN32) static float ftdiff(const FILETIME& b, const FILETIME& a) { uint64 aa = *reinterpret_cast<const uint64*>(&a); uint64 bb = *reinterpret_cast<const uint64*>(&b); return (bb - aa) * 1e-7f; } class CCPUMonitor { public: CCPUMonitor(ISystem* pSystem, int nCPUs) : m_lastUpdate(0.0f) , m_pTimer(pSystem->GetITimer()) , m_nCPUs(nCPUs) { FILETIME notNeeded; GetProcessTimes(GetCurrentProcess(), ¬Needed, ¬Needed, &m_lastKernel, &m_lastUser); } float* Update() { CTimeValue frameTime = gEnv->pTimer->GetFrameStartTime(); if (frameTime - m_lastUpdate > 5.0f) { m_lastUpdate = frameTime; static float result = 0.0f; FILETIME kernel, user, cur; FILETIME notNeeded; GetSystemTimeAsFileTime(&cur); GetProcessTimes(GetCurrentProcess(), ¬Needed, ¬Needed, &kernel, &user); float sKernel = ftdiff(kernel, m_lastKernel); float sUser = ftdiff(user, m_lastUser); float sCur = ftdiff(cur, m_lastTime); result = 100 * (sKernel + sUser) / sCur / m_nCPUs; m_lastTime = cur; m_lastKernel = kernel; m_lastUser = user; return &result; } return 0; } private: ITimer* m_pTimer; CTimeValue m_lastUpdate; FILETIME m_lastKernel, m_lastUser, m_lastTime; int m_nCPUs; }; #else class CCPUMonitor { public: CCPUMonitor(ISystem* pSystem, int nCPUs) {} float* Update() { return 0; } }; #endif CServerThrottle::CServerThrottle(ISystem* pSys, int nCPUs) { m_pCPUMonitor.reset(new CCPUMonitor(pSys, nCPUs)); m_pDedicatedMaxRate = pSys->GetIConsole()->GetCVar("sv_DedicatedMaxRate"); m_pDedicatedCPU = pSys->GetIConsole()->GetCVar("sv_DedicatedCPUPercent"); m_pDedicatedCPUVariance = pSys->GetIConsole()->GetCVar("sv_DedicatedCPUVariance"); m_minFPS = 20; m_maxFPS = 60; m_nSteps = 8; m_nCurStep = 0; if (m_pDedicatedCPU->GetFVal() >= 1.0f) { SetStep(m_nSteps / 2, 0); } } CServerThrottle::~CServerThrottle() { } void CServerThrottle::Update() { float tgtCPU = m_pDedicatedCPU->GetFVal(); if (tgtCPU < 1) { return; } if (float* pCPU = m_pCPUMonitor->Update()) { float varCPU = m_pDedicatedCPUVariance->GetFVal(); if (tgtCPU < 5) { tgtCPU = 5; } else if (tgtCPU > 95) { tgtCPU = 95; } float minCPU = std::max(tgtCPU - varCPU, tgtCPU / 2.0f); float maxCPU = std::min(tgtCPU + varCPU, (100.0f + tgtCPU) / 2.0f); if (*pCPU > maxCPU) { SetStep(m_nCurStep - 1, pCPU); } else if (*pCPU < minCPU) { SetStep(m_nCurStep + 1, pCPU); } } } void CServerThrottle::SetStep(int step, float* pDueToCPU) { if (step < 0) { step = 0; } else if (step > m_nSteps) { step = m_nSteps; } if (step != m_nCurStep) { float fps = step * (m_maxFPS - m_minFPS) / m_nSteps + m_minFPS; m_pDedicatedMaxRate->Set(fps); if (pDueToCPU) { CryLog("ServerThrottle: Set framerate to %.1f fps [due to cpu being %d%%]", fps, int(*pDueToCPU + 0.5f)); } else { CryLog("ServerThrottle: Set framerate to %.1f fps", fps); } m_nCurStep = step; } }