Files
nxnative-easy/docs/agents/symptoms.md
T
seedds 4db4c69f0b Port Donkey Kong Country: Tropical Freeze 1.0.2
Profile 0100C1F0051B6000 (SDK 4.4.0, Retro Studios' engine, NVN): plays on the Mac from boot
through the menus and the intro cinematic into the first level at 60 fps. General changes:

- svc SetHeapSize: a request beyond the heap region returns ResultOutOfMemory, as Horizon
  (the game binary-searches its heap size between 3 and 6 GB)
- shader_split.py: SNVN program records in Retro's RFRM forms (MaterialArchive.arc, the packs'
  MTRL resources) and the LZSS-compressed startup material archive in main
- nvn_mtl.m: a texture in a CPU_UNCACHED pool starts with its storage at first use (title logo,
  menu panels); transform feedback captures draws that rasterize too
- dmsh_build.py: transform feedback buffers holding several outputs (DK's fur simulation);
  chain header regenerated
- hle_audren.c: the renderer event is the kernel event the audio service gives, not the SDK's
  local one (the main thread was starved at the first level's load)
- hle_oe.c: oe::GetUserInactivityDetectionTimeExtensionMode
2026-10-26 22:38:18 +08:00

114 KiB
Raw Blame History

Symptom index

One line per symptom in the subsystem references: what you see (an assertion, a [RED] line, an abort or crash site, a visible result) and the entry that explains it. Search this page for the text in your log first (grep -i the function name, the [RED] text or the address form), then read the entry and the game notes it names. Generated by dm/tools/docs_symptoms.py from the entries' Symptom bullets: change the entry, then run it.

Packing

Rewriter

Memory and address space

Threads

  • a parent returns from StartThread before a newly runnable higher-priority child pinned to its core finishes its work (deterministic regression, not attributed to a game failure). → Starting a higher-priority thread on the caller's core
  • per-core job queues never drained. → Core mask changes move the ideal core into the new mask
  • crash indexing a per-core table with a huge offset (index −2). → Ideal core −2 resolves to the process default core
  • the main thread waits forever on an event right after nnMain starts, with only three or four threads created; DM_THR=1 shows no CreateThread for the thread it waits on. → Free thread count (svcGetInfo type 24)
  • in garbage-collected titles (Unity / IL2CPP), live objects freed, with their finalizers releasing native resources. → Pausing threads and reading their context for garbage collectors
  • crashes around movie changes in the game's own player threads, about one run in two: SignalEvent → MultiWaitImpl::NotifyAndWakeupThread on a null MultiWait at address 0x20; WaitAny walking freed holders; a worker reading a freed object at main+0x225338. The other way round, a handoff that waits too widely: a black screen at boot that never loads a texture (packaged textures: first uploads 0), or a load that never ends behind an animated loading screen, with the thread dump's same-core handoffs N, total T ms larger than the run itself. → Same-core wake handoffs
  • several threads crash at once and the dumps interleave, then the process hangs instead of exiting. → Simultaneous crashes of several threads
  • none seen; found while investigating Fire Emblem Engage's demo crash, which it did not change (that was the address-space shortage, Size-aligned regions exhaust the alias address space). → SignalToAddress type 2 with count ≤ 0
  • a 64-bit wait could return at once or block when it should not (not met in a game). → WaitForAddress type 3: 64-bit wait if equal
  • a PhysX worker crashes in a task's removeReference with a null task manager, right as the game switches to 30 fps (pc=main+0x10ccf28, lr=main+0x13c236c); on the iPhone and in 2 of 5 Mac runs, in every Mac run with 12 busy loops loading the CPU. → Late PhysX task destructor after the unlock
  • a 30 Hz game thread runs at 27 Hz, and whatever it paces comes out slow (cutscenes at 36 ms per frame instead of 33.3; gameplay was fine at 60). → Timer slack in guest sleeps (sleep_precise)
  • a guest thread keeps a core at 100% with billions of SleepThread calls. → Sleeps under 20 µs take the yield path
  • a loading screen sits for a minute with the CPU nearly idle; one thread yields thousands of times a second, every yield a back-off sleep (the power line's top yielder, with as many back-off sleeps). → Yields that make progress return at once (thr_yield)
  • a host helper thread aborts when signalling a destroyed SystemEvent; repeated vi::GetDisplayVsyncEvent calls double the event's tick rate. Rapid replacement can abort with too many vsync events, or a retired vsync worker can signal another service's event at reused storage. → Service-event producers follow the binding lifetime
  • the main thread waits forever on a job's done event at boot while every worker sleeps, two of them on one event (main+0x1426c waiting on Job::m_doneEvent); 4 of 6 Mac runs. → One auto-clear event shared by a pool's workers
  • abort in os::WaitSystemEvent under oe::PopNotificationMessage (The Legend of Zelda: Link's Awakening); one guest thread at about 1000 ms/s on the iPhone only, the phone hot, CPU energy 5–7 W (Monster Hunter Rise's MessageSuperviseThread, priority 32, in the [nvn] threads lines). → The oe notification event and its queue

Services and SDK calls

Movies

Audio

Frame rate

NVN objects

Rendering

Shaders

Game state