Core: Use multiplexer to idle sleep for GDB server

pull/3782/head
Stenzek 2 months ago
parent 30fa5b4c4e
commit c7f282f184
No known key found for this signature in database

@ -799,7 +799,7 @@ float Core::GetProcessUptime()
return static_cast<float>(Timer::ConvertValueToSeconds(Timer::GetCurrentValue() - s_locals.process_start_time));
}
void Core::IdleUpdate()
void Core::IdleUpdate(u64 max_poll_time)
{
InputManager::PollSources();
@ -812,6 +812,6 @@ void Core::IdleUpdate()
Achievements::IdleUpdate();
#ifdef ENABLE_GDB_SERVER
GDBServer::Poll(0);
GDBServer::PollUntil(max_poll_time);
#endif
}

@ -48,7 +48,7 @@ bool CoreThreadInitialize(bool disable_worker_threads, Error* error);
void CoreThreadShutdown();
/// Called to poll input when the session is not running.
void IdleUpdate();
void IdleUpdate(u64 max_poll_time);
} // namespace Core

@ -16,6 +16,7 @@
#include "common/small_string.h"
#include "common/string_util.h"
#include "common/thirdparty/SmallVector.h"
#include "common/timer.h"
#include "util/sockets.h"
@ -1038,10 +1039,30 @@ bool GDBServer::HasAnyClients()
return !s_locals.clients.empty();
}
void GDBServer::Poll(u32 timeout_ms)
void GDBServer::PollUntil(u64 max_poll_time)
{
if (s_locals.multiplexer)
s_locals.multiplexer->PollEventsWithTimeout(timeout_ms);
if (!s_locals.multiplexer)
return;
if (max_poll_time == 0)
{
s_locals.multiplexer->PollEventsWithTimeout(0);
return;
}
// Keep polling until we time out, because there could be multiple back<->forth packets.
// Break out if our pause state changes, because we'll probably need to run a frame.
const bool was_running = System::IsRunning();
const bool exact = (was_running && g_settings.display_optimal_frame_pacing);
Timer::Value poll_start_time = Timer::GetCurrentValue();
for (;;)
{
const u32 sleep_ms = static_cast<u32>(Timer::ConvertValueToMilliseconds(max_poll_time - poll_start_time));
s_locals.multiplexer->PollEventsWithTimeout(sleep_ms);
poll_start_time = Timer::GetCurrentValue();
if (poll_start_time >= max_poll_time || System::IsRunning() != was_running || (!exact && sleep_ms == 0))
break;
}
}
void GDBServer::Shutdown()

@ -16,7 +16,7 @@ namespace GDBServer {
bool Initialize(u16 port);
bool HasAnyClients();
void Poll(u32 timeout_ms);
void PollUntil(u64 max_poll_time);
void Shutdown();
void OnSystemPaused();

@ -2044,7 +2044,7 @@ void System::FrameDone()
#endif
#ifdef ENABLE_GDB_SERVER
GDBServer::Poll(0);
GDBServer::PollUntil(0);
#endif
// Save states for rewind and runahead.
@ -2261,15 +2261,7 @@ void System::Throttle(Timer::Value current_time, Timer::Value sleep_until)
// That way in a query->response->query->response chain, we don't process only one message per frame.
if (GDBServer::HasAnyClients())
{
Timer::Value poll_start_time = current_time;
for (;;)
{
const u32 sleep_ms = static_cast<u32>(Timer::ConvertValueToMilliseconds(sleep_until - poll_start_time));
GDBServer::Poll(sleep_ms);
poll_start_time = Timer::GetCurrentValue();
if (poll_start_time >= sleep_until || (!g_settings.display_optimal_frame_pacing && sleep_ms == 0))
break;
}
GDBServer::PollUntil(sleep_until);
}
else
#endif
@ -5152,7 +5144,7 @@ void System::DoRewind()
VideoThread::PresentCurrentFrame();
Host::PumpMessagesOnCoreThread();
Core::IdleUpdate();
Core::IdleUpdate(s_state.next_frame_time);
// get back into it straight away if we're no longer rewinding
if (!IsRewinding())

@ -115,7 +115,7 @@ static constexpr int IDLE_UPDATE_INTERVAL_WITH_FULLSCREEN_UI = 8;
static constexpr int IDLE_UPDATE_INTERVAL_WHILE_DOWNLOADING = 10;
/// Poll at 1ms when running GDB server. We can get rid of this once we move networking to its own thread.
static constexpr int IDLE_UPDATE_INTERVAL_WITH_GDB_CLIENTS = 1;
static constexpr int IDLE_UPDATE_INTERVAL_WITH_GDB_CLIENTS = 10;
//////////////////////////////////////////////////////////////////////////
// Local function declarations
@ -2092,7 +2092,7 @@ void CoreThread::createIdleUpdateTimer()
m_idle_update_timer = new QTimer(this);
m_idle_update_timer->setSingleShot(false);
m_idle_update_timer->setTimerType(Qt::CoarseTimer);
connect(m_idle_update_timer, &QTimer::timeout, &Core::IdleUpdate);
connect(m_idle_update_timer, &QTimer::timeout, this, &CoreThread::onIdleUpdateTimer);
}
void CoreThread::destroyIdleUpdateTimer()
@ -2123,6 +2123,25 @@ void CoreThread::stopIdleUpdateTimer()
m_idle_update_timer->stop();
}
void CoreThread::onIdleUpdateTimer()
{
if (!m_has_gdb_clients)
{
Core::IdleUpdate(0);
return;
}
// When we have gdb clients, use the multiplexer to sleep instead. that way round-trips can
// be responded to as quickly as possible.
//
// NOTE: This is kinda screwy, because it'll block RunOnCoreThread() callbacks from running
// while we're polling. Hence why it's still capped at 10ms.
const int timeout = m_idle_update_timer->interval();
const u64 poll_until = Timer::GetCurrentValue() + Timer::ConvertMillisecondsToValue(static_cast<u32>(timeout));
Core::IdleUpdate(poll_until);
}
void CoreThread::updateIdleTimerInterval()
{
if (!isCurrentThread())
@ -2145,13 +2164,10 @@ void CoreThread::updateIdleTimerInterval()
int CoreThread::getBackgroundControllerPollInterval() const
{
#ifdef ENABLE_GDB_SERVER
if (GDBServer::HasAnyClients())
return IDLE_UPDATE_INTERVAL_WITH_GDB_CLIENTS;
#endif
if (m_video_thread_run_idle)
return IDLE_UPDATE_INTERVAL_WITH_FULLSCREEN_UI;
else if (m_has_gdb_clients)
return IDLE_UPDATE_INTERVAL_WITH_GDB_CLIENTS;
else if (m_http_downloader_active)
return IDLE_UPDATE_INTERVAL_WHILE_DOWNLOADING;
else if (InputManager::GetPollableDeviceCount() > 0)
@ -2173,6 +2189,18 @@ void CoreThread::setHTTPDownloaderActive(bool active)
updateIdleTimerInterval();
}
void CoreThread::setGDBActiveClients(bool active)
{
if (!isCurrentThread())
{
QMetaObject::invokeMethod(this, &CoreThread::setGDBActiveClients, Qt::QueuedConnection, active);
return;
}
m_has_gdb_clients = active;
updateIdleTimerInterval();
}
void CoreThread::setVideoThreadRunIdle(bool active)
{
if (!isCurrentThread())
@ -2214,7 +2242,7 @@ void Host::OnHTTPDownloaderActiveChanged(bool active)
void Host::OnGDBServerActiveClientsChanged(bool has_clients)
{
g_core_thread->updateIdleTimerInterval();
g_core_thread->setGDBActiveClients(has_clients);
}
void CoreThread::stop()

@ -183,6 +183,7 @@ public:
void startControllerTest();
void openGamePropertiesForCurrentGame(const QString& category = {});
void setHTTPDownloaderActive(bool active);
void setGDBActiveClients(bool active);
void setVideoThreadRunIdle(bool active);
void updateFullscreenUITheme();
void runOnCoreThread(const std::function<void()>& callback);
@ -205,6 +206,7 @@ private:
void createIdleUpdateTimer();
void destroyIdleUpdateTimer();
void onIdleUpdateTimer();
void bootOrLoadState(std::string path);
@ -218,6 +220,7 @@ private:
bool m_shutdown_flag = false;
bool m_http_downloader_active = false;
bool m_has_gdb_clients = false;
bool m_video_thread_run_idle = false;
bool m_is_fullscreen_ui_started = false;
bool m_was_paused_by_focus_loss = false;

Loading…
Cancel
Save