1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 18:53:28 +01:00

Timers scaling and fixes

This commit is contained in:
Eladash 2019-07-14 06:55:11 +03:00 committed by Ani
parent d17be2c2ec
commit 85b1152e29
27 changed files with 160 additions and 162 deletions

View File

@ -1259,7 +1259,7 @@ void camera_context::operator()()
continue;
}
const u64 frame_start = get_system_time();
const u64 frame_start = get_guest_system_time();
std::unique_lock lock(mutex_notify_data_map);
@ -1304,7 +1304,7 @@ void camera_context::operator()()
for (const u64 frame_target_time = 1000000u / fps;;)
{
const u64 time_passed = get_system_time() - frame_start;
const u64 time_passed = get_guest_system_time() - frame_start;
if (time_passed >= frame_target_time)
break;

View File

@ -38,7 +38,7 @@ void mic_context::operator()()
continue;
}
const u64 stamp0 = get_system_time();
const u64 stamp0 = get_guest_system_time();
const u64 time_pos = stamp0 - start_time - Emu.GetPauseTime();
const u64 expected_time = m_counter * 256 * 1000000 / 48000;

View File

@ -254,7 +254,7 @@ public:
std::unordered_map<u8, microphone_device> mic_list;
protected:
const u64 start_time = get_system_time();
const u64 start_time = get_guest_system_time();
u64 m_counter = 0;
// u32 signalStateLocalTalk = 9; // value is in range 0-10. 10 indicates talking, 0 indicating none.

View File

@ -332,8 +332,8 @@ error_code cellMsgDialogClose(f32 delay)
{
cellSysutil.warning("cellMsgDialogClose(delay=%f)", delay);
extern u64 get_system_time();
const u64 wait_until = get_system_time() + static_cast<s64>(std::max<float>(delay, 0.0f) * 1000);
extern u64 get_guest_system_time();
const u64 wait_until = get_guest_system_time() + static_cast<s64>(std::max<float>(delay, 0.0f) * 1000);
if (auto manager = fxm::get<rsx::overlays::display_manager>())
{
@ -341,7 +341,7 @@ error_code cellMsgDialogClose(f32 delay)
{
thread_ctrl::spawn("cellMsgDialogClose() Thread", [=]
{
while (get_system_time() < wait_until)
while (get_guest_system_time() < wait_until)
{
if (Emu.IsStopped())
return;
@ -368,7 +368,7 @@ error_code cellMsgDialogClose(f32 delay)
thread_ctrl::spawn("cellMsgDialogClose() Thread", [=]()
{
while (dlg->state == MsgDialogState::Open && get_system_time() < wait_until)
while (dlg->state == MsgDialogState::Open && get_guest_system_time() < wait_until)
{
if (Emu.IsStopped()) return;

View File

@ -113,16 +113,16 @@ s32 cellVpostExec(u32 handle, vm::cptr<u8> inPicBuff, vm::cptr<CellVpostCtrlPara
picInfo->reserved1 = 0;
picInfo->reserved2 = 0;
//u64 stamp0 = get_system_time();
//u64 stamp0 = get_guest_system_time();
std::unique_ptr<u8[]> pA(new u8[w*h]);
memset(pA.get(), ctrlParam->outAlpha, w*h);
//u64 stamp1 = get_system_time();
//u64 stamp1 = get_guest_system_time();
vpost->sws = sws_getCachedContext(vpost->sws, w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
//u64 stamp2 = get_system_time();
//u64 stamp2 = get_guest_system_time();
const u8* in_data[4] = { &inPicBuff[0], &inPicBuff[w * h], &inPicBuff[w * h * 5 / 4], pA.get() };
int in_line[4] = { w, w/2, w/2, w };
@ -132,7 +132,7 @@ s32 cellVpostExec(u32 handle, vm::cptr<u8> inPicBuff, vm::cptr<CellVpostCtrlPara
sws_scale(vpost->sws, in_data, in_line, 0, h, out_data, out_line);
//ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)",
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_guest_system_time() - stamp3);
return CELL_OK;
}

View File

@ -346,7 +346,7 @@ struct surmixer_thread : ppu_thread
if (port.state == audio_port_state::started)
{
//u64 stamp0 = get_system_time();
//u64 stamp0 = get_guest_system_time();
memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata));
if (g_surmx.cb)
@ -355,7 +355,7 @@ struct surmixer_thread : ppu_thread
lv2_obj::sleep(*this);
}
//u64 stamp1 = get_system_time();
//u64 stamp1 = get_guest_system_time();
{
std::lock_guard lock(g_surmx.mutex);
@ -434,7 +434,7 @@ struct surmixer_thread : ppu_thread
}
}
//u64 stamp2 = get_system_time();
//u64 stamp2 = get_guest_system_time();
auto buf = vm::_ptr<f32>(port.addr.addr() + (g_surmx.mixcount % port.num_blocks) * port.num_channels * AUDIO_BUFFER_SAMPLES * sizeof(float));
@ -444,7 +444,7 @@ struct surmixer_thread : ppu_thread
*buf++ = mixdata;
}
//u64 stamp3 = get_system_time();
//u64 stamp3 = get_guest_system_time();
//ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2);
}

View File

@ -11,7 +11,7 @@
LOG_CHANNEL(sysPrxForUser);
extern u64 get_system_time();
extern u64 get_guest_system_time();
vm::gvar<s32> sys_prx_version; // ???
vm::gvar<vm::ptr<void()>> g_ppu_atexitspawn;
@ -22,7 +22,7 @@ s64 sys_time_get_system_time()
{
sysPrxForUser.trace("sys_time_get_system_time()");
return get_system_time();
return get_guest_system_time();
}
void sys_process_exit(ppu_thread& ppu, s32 status)

View File

@ -214,7 +214,7 @@ error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64
return CELL_OK;
}
const u64 time0 = timeout ? get_system_time() : 0;
const u64 time0 = timeout ? get_guest_system_time() : 0;
const error_code res_ = _sys_lwmutex_lock(ppu, lwmutex->sleep_queue, timeout);
@ -229,7 +229,7 @@ error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64
}
else if (timeout && res_ != CELL_ETIMEDOUT)
{
const u64 time_diff = get_system_time() - time0;
const u64 time_diff = get_guest_system_time() - time0;
if (timeout <= time_diff)
{

View File

@ -10,8 +10,6 @@
extern logs::channel sysPrxForUser;
extern u64 get_system_time();
spu_printf_cb_t g_spu_printf_agcb;
spu_printf_cb_t g_spu_printf_dgcb;
spu_printf_cb_t g_spu_printf_atcb;

View File

@ -64,7 +64,7 @@ const bool s_use_ssse3 =
#define _mm_shuffle_epi8
#endif
extern u64 get_system_time();
extern u64 get_guest_system_time();
extern atomic_t<const char*> g_progr;
extern atomic_t<u64> g_progr_ptotal;
@ -469,7 +469,7 @@ std::string ppu_thread::dump() const
if (const auto _time = start_time)
{
fmt::append(ret, "Waiting: %fs\n", (get_system_time() - _time) / 1000000.);
fmt::append(ret, "Waiting: %fs\n", (get_guest_system_time() - _time) / 1000000.);
}
else
{
@ -721,7 +721,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
, prio(prio)
, stack_size(param.stack_size)
, stack_addr(param.stack_addr)
, start_time(get_system_time())
, start_time(get_guest_system_time())
, joiner(-!!detached)
, ppu_name(name)
{
@ -846,7 +846,7 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
{
if (start_time)
{
LOG_WARNING(PPU, "'%s' aborted (%fs)", current_function, (get_system_time() - start_time) / 1000000.);
LOG_WARNING(PPU, "'%s' aborted (%fs)", current_function, (get_guest_system_time() - start_time) / 1000000.);
}
else
{

View File

@ -999,7 +999,7 @@ extern ppu_function_t ppu_get_syscall(u64 code)
return nullptr;
}
extern u64 get_system_time();
extern u64 get_guest_system_time();
DECLARE(lv2_obj::g_mutex);
DECLARE(lv2_obj::g_ppu);
@ -1010,7 +1010,7 @@ void lv2_obj::sleep_timeout(cpu_thread& thread, u64 timeout)
{
std::lock_guard lock(g_mutex);
const u64 start_time = get_system_time();
const u64 start_time = get_guest_system_time();
if (auto ppu = static_cast<ppu_thread*>(thread.id_type() == 1 ? &thread : nullptr))
{
@ -1040,7 +1040,7 @@ void lv2_obj::sleep_timeout(cpu_thread& thread, u64 timeout)
ppu->start_time = start_time;
}
if (timeout)
if (timeout && g_cfg.core.sleep_timers_accuracy != sleep_timers_accuracy_level::_all_timers)
{
const u64 wait_until = start_time + timeout;
@ -1078,7 +1078,7 @@ void lv2_obj::awake(cpu_thread& cpu, u32 prio)
else if (prio == -4)
{
// Yield command
const u64 start_time = get_system_time();
const u64 start_time = get_guest_system_time();
for (std::size_t i = 0, pos = -1; i < g_ppu.size(); i++)
{
@ -1184,7 +1184,7 @@ void lv2_obj::schedule_all()
{
auto& pair = g_waiting.front();
if (pair.first <= get_system_time())
if (pair.first <= get_guest_system_time())
{
pair.second->notify();
g_waiting.pop_front();

View File

@ -12,8 +12,6 @@ LOG_CHANNEL(sys_cond);
template<> DECLARE(ipc_manager<lv2_cond, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
{
vm::temporary_unlock(ppu);
@ -262,9 +260,7 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(cond->mutex->mutex);
@ -285,8 +281,6 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
timeout = 0;
continue;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -14,8 +14,6 @@ LOG_CHANNEL(sys_event);
template<> DECLARE(ipc_manager<lv2_event_queue, u64>::g_ipc) {};
extern u64 get_system_time();
std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
{
if (ipc_key == SYS_EVENT_QUEUE_LOCAL)
@ -284,9 +282,7 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(queue->mutex);
@ -299,8 +295,6 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -14,8 +14,6 @@ LOG_CHANNEL(sys_event_flag);
template<> DECLARE(ipc_manager<lv2_event_flag, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init)
{
vm::temporary_unlock(ppu);
@ -171,9 +169,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(flag->mutex);
@ -188,8 +184,6 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
ppu.gpr[6] = flag->pattern;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -10,8 +10,6 @@
LOG_CHANNEL(sys_lwcond);
extern u64 get_system_time();
error_code _sys_lwcond_create(ppu_thread& ppu, vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5)
{
vm::temporary_unlock(ppu);
@ -313,9 +311,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(cond->mutex);
@ -330,8 +326,6 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -9,8 +9,6 @@
LOG_CHANNEL(sys_lwmutex);
extern u64 get_system_time();
error_code _sys_lwmutex_create(ppu_thread& ppu, vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> control, s32 has_name, u64 name)
{
vm::temporary_unlock(ppu);
@ -130,9 +128,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(mutex->mutex);
@ -145,8 +141,6 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -12,8 +12,6 @@ LOG_CHANNEL(sys_mutex);
template<> DECLARE(ipc_manager<lv2_mutex, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr)
{
vm::temporary_unlock(ppu);
@ -165,9 +163,7 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(mutex->mutex);
@ -180,8 +176,6 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -30,8 +30,6 @@ static std::vector<ppu_thread*> s_to_awake;
static shared_mutex s_nw_mutex;
extern u64 get_system_time();
// Error helper functions
static s32 get_last_error(bool is_blocking, int native_error = 0)
{
@ -1613,9 +1611,7 @@ s32 sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 nfds, s3
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard nw_lock(s_nw_mutex);
@ -1628,8 +1624,6 @@ s32 sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 nfds, s3
network_clear_queue(ppu);
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{
@ -1814,9 +1808,7 @@ s32 sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set> readf
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard nw_lock(s_nw_mutex);
@ -1829,8 +1821,6 @@ s32 sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set> readf
network_clear_queue(ppu);
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -12,8 +12,6 @@ LOG_CHANNEL(sys_rwlock);
template<> DECLARE(ipc_manager<lv2_rwlock, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr)
{
vm::temporary_unlock(ppu);
@ -140,9 +138,7 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(rwlock->mutex);
@ -155,8 +151,6 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{
@ -341,9 +335,7 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(rwlock->mutex);
@ -371,8 +363,6 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -12,8 +12,6 @@ LOG_CHANNEL(sys_semaphore);
template<> DECLARE(ipc_manager<lv2_sema, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
{
vm::temporary_unlock(ppu);
@ -134,9 +132,7 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
if (timeout)
{
const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout)
if (lv2_obj::wait_timeout(timeout, &ppu))
{
std::lock_guard lock(sem->mutex);
@ -157,8 +153,6 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
ppu.gpr[3] = CELL_ETIMEDOUT;
break;
}
thread_ctrl::wait_for(timeout - passed);
}
else
{

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Utilities/mutex.h"
#include "Utilities/sema.h"
@ -9,8 +9,10 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/System.h"
#include <deque>
#include <thread>
// attr_protocol (waiting scheduling policy)
enum
@ -213,6 +215,68 @@ struct lv2_obj
}
}
template<bool is_usleep = false>
static bool wait_timeout(u64 usec, cpu_thread* const cpu = nullptr)
{
usec = (usec * g_cfg.core.clocks_scale) / 100;
#ifdef __linux__
// TODO: Confirm whether Apple or any BSD can benefit from this as well
constexpr u32 host_min_quantum = 50;
#else
// Host scheduler quantum for windows (worst case)
// NOTE: On ps3 this function has very high accuracy
constexpr u32 host_min_quantum = 500;
#endif
extern u64 get_system_time();
u64 passed = 0;
u64 remaining;
const u64 start_time = get_system_time();
while (usec >= passed)
{
remaining = usec - passed;
if (g_cfg.core.sleep_timers_accuracy < (is_usleep ? sleep_timers_accuracy_level::_usleep : sleep_timers_accuracy_level::_all_timers))
{
thread_ctrl::wait_for(remaining);
}
else
{
if (remaining > host_min_quantum)
{
#ifdef __linux__
// Do not wait for the last quantum to avoid loss of accuracy
thread_ctrl::wait_for(remaining - ((remaining % host_min_quantum) + host_min_quantum));
#else
// Wait on multiple of min quantum for large durations to avoid overloading low thread cpus
thread_ctrl::wait_for(remaining - (remaining % host_min_quantum));
#endif
}
else
{
// Try yielding. May cause long wake latency but helps weaker CPUs a lot by alleviating resource pressure
std::this_thread::yield();
}
}
if (Emu.IsStopped())
{
return false;
}
if (cpu && cpu->state & cpu_flag::signal)
{
return false;
}
passed = get_system_time() - start_time;
}
return true;
}
private:
// Scheduler mutex
static shared_mutex g_mutex;

View File

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "sys_time.h"
#include "Emu/System.h"
@ -102,11 +102,9 @@ static int clock_gettime(int clk_id, struct timespec* tp)
#endif
LOG_CHANNEL(sys_time);
static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz
static constexpr u64 g_timebase_freq = /*79800000*/ 80000000ull; // 80 Mhz
// Auxiliary functions
u64 get_timebased_time()
@ -118,12 +116,12 @@ u64 get_timebased_time()
const u64 time = count.QuadPart;
const u64 freq = s_time_aux_info.perf_freq;
return time / freq * g_timebase_freq + time % freq * g_timebase_freq / freq;
return (time / freq * g_timebase_freq + time % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u;
#else
struct timespec ts;
verify(HERE), ::clock_gettime(CLOCK_MONOTONIC, &ts) == 0;
return static_cast<u64>(ts.tv_sec) * g_timebase_freq + static_cast<u64>(ts.tv_nsec) * g_timebase_freq / 1000000000u;
return (static_cast<u64>(ts.tv_sec) * g_timebase_freq + static_cast<u64>(ts.tv_nsec) * g_timebase_freq / 1000000000ull) * g_cfg.core.clocks_scale / 100u;
#endif
}
@ -139,18 +137,24 @@ u64 get_system_time()
const u64 time = count.QuadPart;
const u64 freq = s_time_aux_info.perf_freq;
const u64 result = time / freq * 1000000u + (time % freq) * 1000000u / freq;
const u64 result = time / freq * 1000000ull + (time % freq) * 1000000ull / freq;
#else
struct timespec ts;
verify(HERE), ::clock_gettime(CLOCK_MONOTONIC, &ts) == 0;
const u64 result = static_cast<u64>(ts.tv_sec) * 1000000u + static_cast<u64>(ts.tv_nsec) / 1000u;
const u64 result = static_cast<u64>(ts.tv_sec) * 1000000ull + static_cast<u64>(ts.tv_nsec) / 1000u;
#endif
if (result) return result;
}
}
// As get_system_time but obeys Clocks scaling setting
u64 get_guest_system_time()
{
return get_system_time() * g_cfg.core.clocks_scale / 100;
}
// Functions
s32 sys_time_get_timezone(vm::ptr<s32> timezone, vm::ptr<s32> summertime)
{
@ -171,24 +175,24 @@ s32 sys_time_get_current_time(vm::ptr<s64> sec, vm::ptr<s64> nsec)
verify(HERE), QueryPerformanceCounter(&count);
// get time difference in nanoseconds
const u64 diff = (count.QuadPart - s_time_aux_info.start_time) * 1000000000u / s_time_aux_info.perf_freq;
const u64 diff = (count.QuadPart - s_time_aux_info.start_time) * 1000000000ull / s_time_aux_info.perf_freq;
// get time since Epoch in nanoseconds
const u64 time = s_time_aux_info.start_ftime * 100u + diff;
const u64 time = (s_time_aux_info.start_ftime * 100u + diff) * g_cfg.core.clocks_scale / 100u;
if (!sec)
{
return CELL_EFAULT;
}
*sec = time / 1000000000u;
*sec = time / 1000000000ull;
if (!nsec)
{
return CELL_EFAULT;
}
*nsec = time % 1000000000u;
*nsec = time % 1000000000ull;
#else
struct timespec ts;
verify(HERE), ::clock_gettime(CLOCK_REALTIME, &ts) == 0;
@ -198,14 +202,14 @@ s32 sys_time_get_current_time(vm::ptr<s64> sec, vm::ptr<s64> nsec)
return CELL_EFAULT;
}
*sec = ts.tv_sec;
*sec = (ts.tv_sec * g_cfg.core.clocks_scale / 100u) + (ts.tv_nsec * g_cfg.core.clocks_scale / (1000000000ull * 100));
if (!nsec)
{
return CELL_EFAULT;
}
*nsec = ts.tv_nsec;
*nsec = (ts.tv_nsec * g_cfg.core.clocks_scale / 100u) % 1000000000ull;
#endif
return CELL_OK;

View File

@ -13,7 +13,7 @@
LOG_CHANNEL(sys_timer);
extern u64 get_system_time();
extern u64 get_guest_system_time();
void lv2_timer_context::operator()()
{
@ -23,7 +23,7 @@ void lv2_timer_context::operator()()
if (_state == SYS_TIMER_STATE_RUN)
{
const u64 _now = get_system_time();
const u64 _now = get_guest_system_time();
const u64 next = expire;
if (_now >= next)
@ -48,7 +48,7 @@ void lv2_timer_context::operator()()
}
// TODO: use single global dedicated thread for busy waiting, no timer threads
thread_ctrl::wait_for(next - _now);
lv2_obj::wait_timeout(next - _now);
}
else if (_state == SYS_TIMER_STATE_STOP)
{
@ -142,7 +142,7 @@ error_code _sys_timer_start(ppu_thread& ppu, u32 timer_id, u64 base_time, u64 pe
sys_timer.trace("_sys_timer_start(timer_id=0x%x, base_time=0x%llx, period=0x%llx)", timer_id, base_time, period);
const u64 start_time = get_system_time();
const u64 start_time = get_guest_system_time();
if (!period && start_time >= base_time)
{
@ -307,46 +307,13 @@ error_code sys_timer_usleep(ppu_thread& ppu, u64 sleep_time)
if (sleep_time)
{
#ifdef __linux__
// TODO: Confirm whether Apple or any BSD can benefit from this as well
constexpr u32 host_min_quantum = 50;
#else
// Host scheduler quantum for windows (worst case)
// NOTE: On ps3 this function has very high accuracy
constexpr u32 host_min_quantum = 500;
#endif
lv2_obj::sleep(ppu, 0);
u64 passed = 0;
u64 remaining;
lv2_obj::wait_timeout<true>(sleep_time);
lv2_obj::sleep(ppu, sleep_time);
while (sleep_time >= passed)
if (ppu.is_stopped())
{
if (ppu.is_stopped())
{
return 0;
}
remaining = sleep_time - passed;
if (remaining > host_min_quantum)
{
#ifdef __linux__
// Do not wait for the last quantum to avoid loss of accuracy
thread_ctrl::wait_for(remaining - ((remaining % host_min_quantum) + host_min_quantum));
#else
// Wait on multiple of min quantum for large durations to avoid overloading low thread cpus
thread_ctrl::wait_for(remaining - (remaining % host_min_quantum));
#endif
}
else
{
// Try yielding. May cause long wake latency but helps weaker CPUs a lot by alleviating resource pressure
std::this_thread::yield();
}
passed = (get_system_time() - ppu.start_time);
return 0;
}
}
else

View File

@ -799,7 +799,7 @@ namespace rsx
u64 thread::timestamp()
{
// Get timestamp, and convert it from microseconds to nanoseconds
const u64 t = get_system_time() * 1000;
const u64 t = get_guest_system_time() * 1000;
if (t != timestamp_ctrl)
{
timestamp_ctrl = t;

View File

@ -20,6 +20,7 @@
#include "Emu/Cell/lv2/sys_rsx.h"
extern u64 get_guest_system_time();
extern u64 get_system_time();
struct RSXIOTable

View File

@ -275,6 +275,22 @@ void fmt_class_string<tsx_usage>::format(std::string& out, u64 arg)
});
}
template <>
void fmt_class_string<sleep_timers_accuracy_level>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](sleep_timers_accuracy_level value)
{
switch (value)
{
case sleep_timers_accuracy_level::_as_host: return "Host";
case sleep_timers_accuracy_level::_usleep: return "Usleep";
case sleep_timers_accuracy_level::_all_timers: return "All";
}
return unknown;
});
}
template <>
void fmt_class_string<enter_button_assign>::format(std::string& out, u64 arg)
{

View File

@ -8,6 +8,7 @@
#include <string>
u64 get_system_time();
u64 get_guest_system_time();
enum class system_state
{
@ -47,6 +48,13 @@ enum class lib_loading_type
liblv2only
};
enum sleep_timers_accuracy_level : u32
{
_as_host = 0,
_usleep,
_all_timers,
};
enum class keyboard_handler
{
null,
@ -406,6 +414,8 @@ struct cfg_root : cfg::node
cfg::set_entry load_libraries{this, "Load libraries"};
cfg::_bool hle_lwmutex{this, "HLE lwmutex"}; // Force alternative lwmutex/lwcond implementation
cfg::_int<10, 1000> clocks_scale{this, "Clocks scale", 100}; // Changing this from 100 (percentage) may affect game speed in unexpected ways
cfg::_enum<sleep_timers_accuracy_level> sleep_timers_accuracy{this, "Sleep timers accuracy", sleep_timers_accuracy_level::_as_host}; // Affects sleep timers accuracy (to fix host's sleep accuracy)
} core{this};
struct node_vfs : cfg::node
@ -477,7 +487,7 @@ struct cfg_root : cfg::node
cfg::_int<0, 16> anisotropic_level_override{this, "Anisotropic Filter Override", 0};
cfg::_int<1, 1024> min_scalable_dimension{this, "Minimum Scalable Dimension", 16};
cfg::_int<0, 30000000> driver_recovery_timeout{this, "Driver Recovery Timeout", 1000000};
cfg::_int<1, 500> vblank_rate{this, "Vblank Rate", 60}; // Changing this from 60 may affect game speed unexpected ways
cfg::_int<1, 500> vblank_rate{this, "Vblank Rate", 60}; // Changing this from 60 may affect game speed in unexpected ways
struct node_d3d12 : cfg::node
{