Files
nxnative-easy/docs/agents/symptoms.md
T
seedds ed3007f1ef Port Kirby and the Forgotten Land 1.1.0
HAL Laboratory's engine on NintendoWare, SDK 11.4.0, NVN. Plays on the Mac at 30 fps, as on
the Switch: online and difficulty prompts, the 1080p opening movie, Point of Arrival with its
guide movies, the city reveal, the Sword ability and fights, title and Continue; a 15-minute
soak with no crash. No game code is cut; the profile is the memory layout and the shader groups.
All 27,297 shaders build for Mac and iOS; the IPA (6.4 GB) is untested on a device.

- Threads (general): a guest thread waiting for a host lock that HLE code holds while it runs
  guest code is blocked, not runnable (dm_host_lock, a native HLE wait). The movie decoder held
  its decode lock across SignalEvent; the signal's same-core handoff waited for the movie input
  thread, which waited for that lock, and the game froze at its first guide movie. t_preempt
  has the case.

Docs: the game note, games table, README gallery, threads.md, shaders.md, symptom index;
AGENTS count 73 -> 74. Checked: host tests, preempt, tool tests (253, 15 skips), docs tests;
a Mac run on chain 5cddc47253ab through the first guide movie.
2026-10-27 02:51:05 +08:00

117 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
  • the game freezes when a movie starts playing beside the game (a guide movie in a corner of the screen): the last frame stays, the process idles at a few percent of a core, and the thread dump shows a lower-priority job thread running/not waiting with its backtrace in the movie player (ReleaseOutputBufferIndex), the main thread waiting for it, and the movie's input thread running/not waiting too. A sample of the process shows the job thread in md_pump → md_event → dm_yield_to_core_peers, and the input thread in h_movie_SendIn → md_pump waiting for a pthread mutex. → A host lock held across a same-core handoff
  • 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
  • Paper Mario: The Thousand-Year Door 1.0.1 stays black before its first frame. The main thread stops at main+0x32796c, after starting SYS_Notification; the priority-28 notifier is in oe::PopNotificationMessage, while the priority-44 main thread waits for its same-core wake handoff. → Native HLE waits release the guest core

Services and SDK calls

Movies

Audio

Frame rate

NVN objects

Rendering

Shaders

Game state