2015-05-24 06:55:12 +02:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2021-07-05 03:22:19 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2008-12-08 06:30:24 +01:00
|
|
|
|
2019-06-14 16:53:46 +02:00
|
|
|
#include "Common/Timer.h"
|
|
|
|
|
2020-07-12 19:36:58 +02:00
|
|
|
#include <chrono>
|
2008-12-08 06:30:24 +01:00
|
|
|
|
2010-01-21 20:55:01 +01:00
|
|
|
#ifdef _WIN32
|
2022-07-18 05:43:47 +02:00
|
|
|
#include <Windows.h>
|
2022-08-07 07:22:14 +02:00
|
|
|
#include <ctime>
|
2022-07-18 05:59:31 +02:00
|
|
|
#include <timeapi.h>
|
2010-11-20 04:24:51 +01:00
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
2010-01-21 20:55:01 +01:00
|
|
|
|
2014-02-20 04:11:52 +01:00
|
|
|
#include "Common/CommonTypes.h"
|
2008-12-08 06:30:24 +01:00
|
|
|
|
2010-01-21 20:55:01 +01:00
|
|
|
namespace Common
|
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
template <typename Clock, typename Duration>
|
|
|
|
static typename Clock::rep time_now()
|
2010-07-22 06:15:11 +02:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
return std::chrono::time_point_cast<Duration>(Clock::now()).time_since_epoch().count();
|
2010-07-22 06:15:11 +02:00
|
|
|
}
|
2009-02-16 07:18:18 +01:00
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
template <typename Duration>
|
|
|
|
static auto steady_time_now()
|
2014-11-19 19:57:12 +01:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
return time_now<std::chrono::steady_clock, Duration>();
|
2014-11-19 19:57:12 +01:00
|
|
|
}
|
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
u64 Timer::NowUs()
|
2014-11-19 19:57:12 +01:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
return steady_time_now<std::chrono::microseconds>();
|
2014-11-19 19:57:12 +01:00
|
|
|
}
|
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
u64 Timer::NowMs()
|
2008-07-12 19:40:22 +02:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
return steady_time_now<std::chrono::milliseconds>();
|
2008-07-12 19:40:22 +02:00
|
|
|
}
|
2008-12-08 06:30:24 +01:00
|
|
|
|
2009-02-16 07:18:18 +01:00
|
|
|
void Timer::Start()
|
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
m_start_ms = NowMs();
|
|
|
|
m_end_ms = 0;
|
|
|
|
m_running = true;
|
2009-02-16 07:18:18 +01:00
|
|
|
}
|
2008-12-08 06:30:24 +01:00
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
void Timer::StartWithOffset(u64 offset)
|
2009-02-16 07:18:18 +01:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
Start();
|
2022-07-18 20:48:20 +02:00
|
|
|
m_start_ms -= offset;
|
2009-02-16 07:18:18 +01:00
|
|
|
}
|
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
void Timer::Stop()
|
2009-02-16 07:18:18 +01:00
|
|
|
{
|
2022-07-18 05:43:47 +02:00
|
|
|
m_end_ms = NowMs();
|
|
|
|
m_running = false;
|
2009-02-16 07:18:18 +01:00
|
|
|
}
|
2010-07-22 06:15:11 +02:00
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
u64 Timer::ElapsedMs() const
|
2009-02-16 07:18:18 +01:00
|
|
|
{
|
2022-07-18 20:48:20 +02:00
|
|
|
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;
|
2008-07-12 19:40:22 +02:00
|
|
|
}
|
2008-12-13 12:57:01 +01:00
|
|
|
|
2009-02-22 13:43:25 +01:00
|
|
|
u64 Timer::GetLocalTimeSinceJan1970()
|
2008-12-13 12:57:01 +01:00
|
|
|
{
|
2022-08-07 07:25:30 +02:00
|
|
|
// 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
|
2010-08-26 21:24:47 +02:00
|
|
|
time_t sysTime, tzDiff, tzDST;
|
2008-12-13 12:57:01 +01:00
|
|
|
time(&sysTime);
|
2016-07-13 22:46:14 +02:00
|
|
|
tm* gmTime = localtime(&sysTime);
|
2010-08-26 21:24:47 +02:00
|
|
|
|
|
|
|
// Account for DST where needed
|
2014-03-10 12:30:55 +01:00
|
|
|
if (gmTime->tm_isdst == 1)
|
2010-08-26 21:24:47 +02:00
|
|
|
tzDST = 3600;
|
|
|
|
else
|
|
|
|
tzDST = 0;
|
|
|
|
|
2008-12-13 12:57:01 +01:00
|
|
|
// Lazy way to get local time in sec
|
|
|
|
gmTime = gmtime(&sysTime);
|
|
|
|
tzDiff = sysTime - mktime(gmTime);
|
|
|
|
|
2016-07-13 22:46:14 +02:00
|
|
|
return static_cast<u64>(sysTime + tzDiff + tzDST);
|
2008-12-13 12:57:01 +01:00
|
|
|
}
|
2009-01-15 07:48:15 +01:00
|
|
|
|
2022-07-18 05:43:47 +02:00
|
|
|
void Timer::IncreaseResolution()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2022-07-18 09:20:26 +02:00
|
|
|
// 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.. :')
|
2022-07-18 05:43:47 +02:00
|
|
|
timeBeginPeriod(1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Timer::RestoreResolution()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
timeEndPeriod(1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-03-28 09:57:34 +01:00
|
|
|
} // Namespace Common
|