aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NX2_NOTES.md3
-rw-r--r--src/video_core/dma_pusher.cpp3
-rw-r--r--src/video_core/engines/kepler_compute.cpp2
-rw-r--r--src/video_core/engines/puller.cpp3
-rw-r--r--src/video_core/macro.cpp5
-rw-r--r--src/video_core/nx2_profile.h10
6 files changed, 23 insertions, 3 deletions
diff --git a/NX2_NOTES.md b/NX2_NOTES.md
index c5856ab8e3..cf076db45e 100644
--- a/NX2_NOTES.md
+++ b/NX2_NOTES.md
@@ -201,6 +201,8 @@ With the patched decoder, games 1/3/4 only leave ~60-110 rare SIMD encodings in
| 137 | 2D blits (Fermi2D) 3.6% on heavy courses | mip chains 64x64..4x1 copied near the GPU-only regions; neither image is GPU-written, so the software blitter (un)swizzles them on the CPU | open (expected for small copies; many of them) |
| 138 | `async_presentation=true` crashed 4 of 8 runs ~26 s in (row 118) | retested after the fence-operation race (row 118) and translation cache race (row 125) were fixed: 0 crashes in 4 runs, screenshots correct | on in the dev config (`async_presentation\default=false`, `async_presentation=true`); every later run is a crash test for it |
| 139 | buffer collector: up to 64 buffers evicted every frame, GPU-written ones downloaded with a GPU wait (~5% of the GPU thread on 8 GB) | it compared the whole device's use (textures, ~6.8 GB) with thresholds from the device size (6.14 GiB reported): aggressive every frame, while the buffers were ~200 MiB | Switch 2 titles collect on the buffers' own size (1 GiB, aggressive 2 GiB) and keep GPU-written buffers outside aggressive mode (c4eaa4b): 0%, presents no longer blocked on those courses (22-26 ms in t23) |
+| 140 | macros ~20% of the GPU thread; the memo's lookups (~76 ns a call in the game, 48 ns in a warm harness) missed the CPU caches | memo records and its map fall out of cache between calls; 4-way last-call slots raised slot hits 48% -> 63% but saved nothing | x86-64 compiler for the Turing MME (a95cedd, `macro_turing_jit.h`, `EDEN_NX2_MME_JIT=0` off): identical to the interpreter on 200,000 recorded calls (`C:\dev\nx2work\mme_test\jit_test.cpp`); in the game 148 ns a call instead of 174, 0 failures, 0 crashes in 3 runs |
+| 141 | draw setup ~6.4 us a draw (55,000 a second) | spread over ~12 steps: uniform buffer copies (2.4%, the fast path streams them every draw and bypasses write tracking), texture views (8.5% incl. ~3.6% streaming new course textures), handle reads, vertex/storage buffer lookups | no single cache-able step; open: small per-step trims. The way past it is a second thread (NX2_GPU_THREAD_SPLIT.md) |
Run settings used (in `build/bin/user/config/sdl2-config.ini`): `memory_layout_mode=4`
(12 GB). Debug knobs: `EDEN_NX2_TC_EXPECTED_MIB` / `EDEN_NX2_TC_CRITICAL_MIB` (collector thresholds),
@@ -214,6 +216,7 @@ faulting stack as module+offset, then a minidump), `EDEN_NX2_AUTO_STUB`, `EDEN_N
`EDEN_NX2_MME_MEMO_STATS` (memo counters),
`EDEN_NX2_BUFFER_DOWNLOADS=0/1`, `EDEN_NX2_INLINE_DEFER=0`, `EDEN_NX2_TC_MIN_AGE=<frames>` (rows 131, 134, 133),
`EDEN_NX2_SKIP_SAME=0` (row 135),
+`EDEN_NX2_MME_JIT=0` (row 140),
`EDEN_NX2_FRAME_CAPTURE=<dir>` (every 120th presented frame as TGA), `EDEN_NX2_PB_CHECK`
(pushbuffer entries changed between submit and execution), `EDEN_NX2_QUERY_TRACE` (every GPU
report/semaphore write). `C:\dev\crashrun.sh` runs eden-cli under cdb and prints the crash stack;
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 3cc5afe967..44a63d789a 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -12,6 +12,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/memory.h"
+#include "video_core/nx2_profile.h"
#include "video_core/dma_pusher.h"
#include "video_core/control/channel_state.h"
#include "video_core/engines/maxwell_3d.h"
@@ -335,6 +336,7 @@ void DmaPusher::CallMethod(u32 argument) {
if (!subchannel->execution_mask[dma_state.method]) {
subchannel->method_sink.emplace_back(dma_state.method, argument);
} else {
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
subchannel->ConsumeSink(system);
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMethod(system, dma_state.method, argument, dma_state.is_last_call);
@@ -356,6 +358,7 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
ReportUnboundSubchannel();
return;
}
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
subchannel->ConsumeSink(system);
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMultiMethod(system, dma_state.method, base_start, num_methods, dma_state.method_count);
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 9102a366a8..ed4e9674b6 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -17,6 +17,7 @@
#include "common/logging.h"
#include "shader_recompiler/exception.h"
#include "core/core.h"
+#include "video_core/nx2_profile.h"
#include "video_core/nx2.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
@@ -171,6 +172,7 @@ bool KeplerCompute::ProcessNativeMethod(Core::System& system, u32 method, u32 ar
if (watched && log_emits) LOG_INFO(HW_GPU, "Semaphore watch: compute macro emit {:#x} = {:#x}", address, value);
if (diagnostic_writes++ < 4096) LOG_DEBUG(HW_GPU, "Native compute MME emit method={:#x}, value={:#x}", address, value);
if (address >= 0xe00) return false;
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
CallMethod(system, address, value, true);
return true;
};
diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp
index b607f20161..c9073f1eb0 100644
--- a/src/video_core/engines/puller.cpp
+++ b/src/video_core/engines/puller.cpp
@@ -11,6 +11,7 @@
#include "common/logging.h"
#include "common/settings.h"
#include "core/core.h"
+#include "video_core/nx2_profile.h"
#include "video_core/control/channel_state.h"
#include "video_core/dma_pusher.h"
#include "video_core/engines/fermi_2d.h"
@@ -217,6 +218,7 @@ void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) {
LOG_ERROR(HW_GPU, "Invalid semaphore operation {}", static_cast<u32>(op));
return;
}
+ VideoCommon::Nx2Profile::Add(VideoCommon::Nx2Profile::Counter::AcquireChecks, 1);
if (acquire.Matches(ReadSemaphoreWord(dma_pusher, acquire.address))) {
return;
}
@@ -229,6 +231,7 @@ void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) {
dma_pusher.rasterizer->ReleaseFences();
if (!waiters.Latched(this) && !acquire.Matches(ReadSemaphoreWord(dma_pusher, acquire.address))) {
pending_acquire = acquire;
+ VideoCommon::Nx2Profile::Add(VideoCommon::Nx2Profile::Counter::AcquireWaits, 1);
} else {
waiters.Remove(this);
}
diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp
index 74e25da067..485b8eaf10 100644
--- a/src/video_core/macro.cpp
+++ b/src/video_core/macro.cpp
@@ -1405,7 +1405,10 @@ void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u
modes[0], modes[1], modes[2], modes[3]);
}
}
- maxwell3d.CallMethod(system, address, value, true);
+ {
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
+ maxwell3d.CallMethod(system, address, value, true);
+ }
// Turing MME memory reads (methods 0x550 SET_MME_MEM_ADDRESS_A/B, 0x558 data RAM
// address, 0x55c MME_DMA_READ into data RAM, 0x560 MME_DMA_READ_FIFOED into
// the load FIFO, which the macro then reads after a load barrier).
diff --git a/src/video_core/nx2_profile.h b/src/video_core/nx2_profile.h
index ccedb7b77d..0c071c85d3 100644
--- a/src/video_core/nx2_profile.h
+++ b/src/video_core/nx2_profile.h
@@ -48,6 +48,7 @@ enum class Zone : u32 {
TextureUpload,
Fence, ///< Fences made (SignalFence)
FenceSkipped, ///< Empty fences not made
+ Method, ///< Engine method calls (what a split GPU thread's back half would run)
Count,
};
@@ -58,7 +59,7 @@ inline constexpr std::array<const char*, static_cast<size_t>(Zone::Count)> zone_
"sync descriptors", "read handles", "fill image views", "texture buffers", "update buffers",
"descriptor acquire", "bind stage buffers", "push descriptors", "render targets",
"configure draw", "dynamic state", "draw record", "texture upload", "fence",
- "fence skipped",
+ "fence skipped", "method",
};
inline bool Enabled() {
@@ -75,7 +76,7 @@ inline u64 Now() {
struct ThreadData {
std::array<u64, static_cast<size_t>(Zone::Count)> exclusive_ns{};
std::array<u64, static_cast<size_t>(Zone::Count)> count{};
- std::array<u64, 6> counters{}; ///< See Counter
+ std::array<u64, 8> counters{}; ///< See Counter
u64 child_ns{}; ///< Time of the zones nested in the current one
u64 window_start{};
};
@@ -123,6 +124,8 @@ enum class Counter : u32 {
DownloadBytesOnDmaPages, ///< Of DownloadBytes: on pages the MME has DMA-read
MethodWrites, ///< 3D register writes (Maxwell3D::CallMethod below the macro range)
SameValueWrites, ///< Of MethodWrites: the register already held the value
+ AcquireChecks, ///< Semaphore acquires evaluated
+ AcquireWaits, ///< Of AcquireChecks: not met yet (the channel waits)
};
/// Device pages (4 KiB) the native MME has DMA-read since start (GPU thread only; filled only
@@ -179,6 +182,9 @@ inline void Report() {
line += fmt::format(" | 3D register writes {:.0f} ({:.0f} same value)",
static_cast<double>(data.counters[4]) * 1e9 / window,
static_cast<double>(data.counters[5]) * 1e9 / window);
+ line += fmt::format(" | acquires {:.0f} ({:.0f} waited)",
+ static_cast<double>(data.counters[6]) * 1e9 / window,
+ static_cast<double>(data.counters[7]) * 1e9 / window);
LOG_INFO(HW_GPU, "GPU thread per second:{}", line);
data = {};
data.window_start = now;