mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-12-28 01:34:27 +01:00
123 lines
3.0 KiB
C++
123 lines
3.0 KiB
C++
// Copyright 2008 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "Common/Timer.h"
|
|
|
|
#include <chrono>
|
|
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#include <ctime>
|
|
#include <timeapi.h>
|
|
#else
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include "Common/CommonTypes.h"
|
|
|
|
namespace Common
|
|
{
|
|
template <typename Clock, typename Duration>
|
|
static typename Clock::rep time_now()
|
|
{
|
|
return std::chrono::time_point_cast<Duration>(Clock::now()).time_since_epoch().count();
|
|
}
|
|
|
|
template <typename Duration>
|
|
static auto steady_time_now()
|
|
{
|
|
return time_now<std::chrono::steady_clock, Duration>();
|
|
}
|
|
|
|
u64 Timer::NowUs()
|
|
{
|
|
return steady_time_now<std::chrono::microseconds>();
|
|
}
|
|
|
|
u64 Timer::NowMs()
|
|
{
|
|
return steady_time_now<std::chrono::milliseconds>();
|
|
}
|
|
|
|
void Timer::Start()
|
|
{
|
|
m_start_ms = NowMs();
|
|
m_end_ms = 0;
|
|
m_running = true;
|
|
}
|
|
|
|
void Timer::StartWithOffset(u64 offset)
|
|
{
|
|
Start();
|
|
m_start_ms -= offset;
|
|
}
|
|
|
|
void Timer::Stop()
|
|
{
|
|
m_end_ms = NowMs();
|
|
m_running = false;
|
|
}
|
|
|
|
u64 Timer::ElapsedMs() const
|
|
{
|
|
const u64 end = m_running ? NowMs() : m_end_ms;
|
|
// Can handle up to 1 rollover event (underflow produces correct result)
|
|
// If Start() has never been called, will return 0
|
|
return end - m_start_ms;
|
|
}
|
|
|
|
u64 Timer::GetLocalTimeSinceJan1970()
|
|
{
|
|
// TODO Would really, really like to use std::chrono here, but Windows did not support
|
|
// std::chrono::current_zone() until 19H1, and other compilers don't even provide support for
|
|
// timezone-related parts of chrono. Someday!
|
|
// see https://bugs.dolphin-emu.org/issues/13007#note-4
|
|
time_t sysTime, tzDiff, tzDST;
|
|
time(&sysTime);
|
|
tm* gmTime = localtime(&sysTime);
|
|
|
|
// Account for DST where needed
|
|
if (gmTime->tm_isdst == 1)
|
|
tzDST = 3600;
|
|
else
|
|
tzDST = 0;
|
|
|
|
// Lazy way to get local time in sec
|
|
gmTime = gmtime(&sysTime);
|
|
tzDiff = sysTime - mktime(gmTime);
|
|
|
|
return static_cast<u64>(sysTime + tzDiff + tzDST);
|
|
}
|
|
|
|
void Timer::IncreaseResolution()
|
|
{
|
|
#ifdef _WIN32
|
|
// Disable execution speed and timer resolution throttling process-wide.
|
|
// This mainly will keep Dolphin marked as high performance if it's in the background. The OS
|
|
// should make it high performance if it's in the foreground anyway (or for some specific
|
|
// threads e.g. audio).
|
|
// This is best-effort (i.e. the call may fail on older versions of Windows, where such throttling
|
|
// doesn't exist, anyway), and we don't bother reverting once set.
|
|
// This adjusts behavior on CPUs with "performance" and "efficiency" cores
|
|
PROCESS_POWER_THROTTLING_STATE PowerThrottling{};
|
|
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
|
|
PowerThrottling.ControlMask =
|
|
PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
|
|
PowerThrottling.StateMask = 0;
|
|
SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling,
|
|
sizeof(PowerThrottling));
|
|
|
|
// Not actually sure how useful this is these days.. :')
|
|
timeBeginPeriod(1);
|
|
#endif
|
|
}
|
|
|
|
void Timer::RestoreResolution()
|
|
{
|
|
#ifdef _WIN32
|
|
timeEndPeriod(1);
|
|
#endif
|
|
}
|
|
|
|
} // Namespace Common
|