We recently spent two days chasing down a major hitch, that ultimately boiled down to two things. First, turns out, Unity doesn't necessarily disable its logging in Release, it silences it. Second, really tall callstacks take a while to format text for. Probably. Best we can tell, anyway.
This was using engine version 2022.3.36f1, for reference.
This started with a major framerate hitch on one of our platforms, on the order of multiple seconds. This was detectable on other platforms but much less substantial, and measuring it in a profiler we saw LogStringToConsole taking around 30ms in the editor, in the right situation. That's already hitch-worthy, but it's not usually that bad and obviously much milder than on our problem platform. So what's going on?
Initially we dismissed this, because in Release logging is disabled, right? But as we started trying things we started being suspicious, since everything else in the area seemed benign and removing other items didn't really move the needle any. We had assistance from QA who tested a few previous builds and verified this wasn't entirely new, but it was dependent on how long you played. Loading into the level and testing it wasn't an issue, but leaving the game to soak for an hour was.
Eventually we got suspicious and removed all the log prints, and the hitch went away, even in Release. Interesting. Suggests Unity doesn't disable its log printing, sure, but why would a log print take so long even if that is the case?
Well, this particular project uses coroutines heavily. It's built partly with Unity's visual scripting and this particular coroutine originates there. It does its work, then at the end of execution it calls itself, and starts another iteration. So over time you have a coroutine starting a coroutine starting a coroutine, basically forever.
Perhaps you've noticed, whenever Unity prints a log print it always includes a callstack in the log. The editor hides this but it's present in the actual log output. Because of the above setup, that callstack inevitably gets longer and longer, eventually being hundreds or thousands of lines long. Why is there a gigantic hitch? Best we can tell, because it's building that massive callstack print and formatting it. On a slower platform, and depending on how it handles logging, this can be very bad. Even on PC it's detectable as a few MS that maybe causes a one-frame skip. On more controlled platforms, it's possibly going through a few layers of operations before it gets to the actual output, and who knows what those are doing
The good news is, you can actually disable logging, by setting Debug.logger.logEnabled to false. This removed the hitch entirely, including its presence in Release builds. So this is what we ultimately did. But it took a long time to figure out this quirk, so here I am documenting it for the public. Hope this saves somebody else some time.