nx2: poll pending channels briefly before sleeping; profile zones on the TSC
- A channel waiting on a semaphore the CPU releases slept 1 ms per poll (~25 waits a second in title 1); poll for 0.5 ms first. - The GPU profile zones read the wall clock (the TSC) instead of QueryPerformanceCounter, which cost ~5% of the GPU thread when on.
This commit is contained in:
parent
8d83cef520
commit
ee9e787fc8
2 changed files with 16 additions and 4 deletions
|
|
@ -39,6 +39,8 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
|
|||
|
||||
auto current_context = context.Acquire();
|
||||
CommandDataContainer next;
|
||||
// When a pending channel last moved or a command arrived (see the polling below).
|
||||
auto last_progress = std::chrono::steady_clock::now();
|
||||
namespace Profile = VideoCommon::Nx2Profile;
|
||||
while (!stop_token.stop_requested()) {
|
||||
Profile::Report();
|
||||
|
|
@ -49,8 +51,16 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
|
|||
scheduler.ResumePending(system.GPU());
|
||||
}
|
||||
if (!state.queue.TryPop(next)) {
|
||||
// The CPU usually releases the semaphore soon after: poll for half a
|
||||
// millisecond before sleeping, or every wait also waits out a host sleep
|
||||
// (title 1 waits ~25 times a second).
|
||||
Profile::Scope scope{Profile::Zone::PendingSleep};
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
if (std::chrono::steady_clock::now() - last_progress <
|
||||
std::chrono::microseconds{500}) {
|
||||
std::this_thread::yield();
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -60,6 +70,7 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
|
|||
if (stop_token.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
last_progress = std::chrono::steady_clock::now();
|
||||
if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
|
||||
Profile::Scope scope{Profile::Zone::Push};
|
||||
scheduler.Push(system.GPU(), submit_list->channel, std::move(submit_list->entries));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/cpu_features.h"
|
||||
|
||||
// EDEN_NX2_GPU_PROFILE: time where the GPU thread spends its time. Each zone counts its own
|
||||
// (exclusive) time, nested zones excluded; every 10 s the thread logs each zone's share.
|
||||
|
|
@ -61,10 +62,10 @@ inline bool Enabled() {
|
|||
return enabled;
|
||||
}
|
||||
|
||||
// Nanoseconds; from the host's own counter where the wall clock reads it directly (the zones
|
||||
// run ~150,000 times a second, and QueryPerformanceCounter cost ~5% of the GPU thread).
|
||||
inline u64 Now() {
|
||||
return static_cast<u64>(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count());
|
||||
return static_cast<u64>(Common::g_wall_clock.GetTimeNS().count());
|
||||
}
|
||||
|
||||
struct ThreadData {
|
||||
|
|
|
|||
Loading…
Reference in a new issue