diff options
| -rw-r--r-- | NX2_NOTES.md | 3 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/engines/kepler_compute.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/engines/puller.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/macro.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/nx2_profile.h | 10 |
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; |
