Atmosphere-NX / Atmosphere

Atmosphère is a work-in-progress customized firmware for the Nintendo Switch.
GNU General Public License v2.0
14.29k stars 1.21k forks source link

Generation of `crash_reports` cause programs hang tens of seconds before crash #2228

Open Coxxs opened 10 months ago

Coxxs commented 10 months ago

Feature Request

What feature are you suggesting?

Overview:

When modding a game, it's very common for incorrect mods to cause the game to crash. However, when such a crash occurs, the game will first hang for tens of seconds (usually 20-30s), before a "The software has been closed due to an error" window pops up, allowing the developer to close the program and check the log. Under OFW, such crashes usually do not hang the program.

This long period of hang is because the crash_report is written line by line, and for a running game with 50+ threads, the report can easily have 4000+ lines (4000+ calls to WriteFile).

https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/creport/source/creport_scoped_file.cpp#L93C29-L93C38

Smaller Details:

Potential solution: When writing crash_reports, adding a Buffer to reduce the number of calls to WriteFile. I believe this can reduce the hang from tens of seconds to <1 second.

Use fs::WriteOption::Flush less frequently may also have the same effect (I'm not familiar with the implementation of fs functions).

Nature of Request:

What component do you feel this would best fit within?

SciresM commented 10 months ago

Well, memory is kind of at a premium. I would prefer not to add client-side buffering unless it's actually necessary. Can you test whether removing WriteOption::Flush gives a speedup?

Coxxs commented 10 months ago

Changing from WriteOption::Flush to WriteOption::None causes a panic from creport (0100000000000036). I guess I may need to Flush it at the correct timing but I'm not familiar with fs and C++...

I tried commenting the fs::WriteFile call completely, and the hang time was reduced from ~36s to ~8s. It seems that the remaining 8 seconds are mostly spent in CrashReport::SaveToFile, probably getting info about modules and threads.

SciresM commented 10 months ago

Yeah, I'm sure a panic when not using option = flush is solvable.

That said, part of why N will be faster is that they don't serialize to plaintext at all; they generate a binary report and save it to internal mmc. In addition, they collect much less information than we do.

I dunno. Let's suppose for purposes of argument that time is reduced from, as you say, ~36 seconds down to ~15 seconds, taking into account the actual writing of the data to disk. Is this substantial, in your eyes, from a usability pov?

Coxxs commented 10 months ago

While waiting for hang, switch can hardly perform any operations (background FTP will also be stuck), so if it's possible to reduce the time by 60% (I guess it will actually be reduced more* with buffered write), it is still very helpful.

* For the crash tested above, the total file size generated is 500 KB (280 KB log [4033 lines] + 121 KB screenshot + 67 KB thread_info)

SciresM commented 10 months ago

Meh, okay. Do you have a test case I can use? I do not actually know how I would trigger a crash in a game for this purpose.

Coxxs commented 10 months ago

Any crash after the game initialized (after creating a lot of threads) should do the trick. I created an empty file at /atmosphere/contents/010015100b514000/romfs/RSDB/ActorInfo.Product.100.rstbl.byml.zs and started SMB Wonder 1.0.0, it crashed with a 205 KB crash log.