Live data from Hacker News

Unity's Mono problem: C# code runs slower than it should

marekfiser.com

171–180 of 190 posts

Re: Unity's Mono problem: C# code runs slower than it should

#171

Earlier quoted context omitted.

While I get that you’re making a stylized comment, it’s a big drag. It’s one of those, “everyone is an idiot except me” styles. By all means, make a game engine that people will adopt based on CoreCLR (or whatever). It’s not saying much that everything has tradeoffs. During the “decade” you are talking about, CoreCLR didn’t have a solution for writing anything for iOS, and today, it isn’t a solution for writing games…

I am sorry that I came across as abrasive, however the points I raised, are as far as I know, factual (and echoed by others' comments). I don't think ignoring them would be constructive. During the 'decade' where CoreCLR was not a solution, Mono (Xamarin) still was - in fact their entire commercial appeal (before they were bought out by Microsoft) was that they provided an AOT compiled .NET for mobile devices. Unity…

I don't think you are off base FWIW. Unity has long both kinda lagged too hard but also just makes things weird at times.

I think the biggest hurdle a unity contender has to overcome, is how to provide both 'similar enough' primitives as well, as a way to easily consistently handle the graphics/sound pipeline (i.e. simple way to handle different platform bindings) while also making sure all of that infrastructure is AOT friendly.

Re: Unity's Mono problem: C# code runs slower than it should

#172
post #95

Earlier quoted context omitted.

Naive question but why not use GDscript? I haven't had any issues with it

I'll add that C# have better performances than gdscript. It doesn't make a difference for most of the things you code in a game, but it comes in handy when needed.

I'd caveat this slightly as "it depends"

For mathy stuff, 100% c# is going to be better. But if you need to round trip to the engine a lot getting stuff in and out of the dotnet heap can actually hurt performance. You also have to be _really_ careful because there are a lot of cases you generate accidental garbage (biggest one is when you use strings that are getting implicitly converted to StringNames every time you run a function, you can avoid this by pre-generating them as consts but I've run into a fair few people who never ran dotmemory or the like to see the issues).

Re: Unity's Mono problem: C# code runs slower than it should

#173

Earlier quoted context omitted.

Author here, thanks for your perspective. Here some thoughts: > approach of separating the simulation and presentation layers isn't all that uncommon I agree that some level of separation is is not that uncommon, but games usually depend on things from their respective engine, especially on things like datatypes (e.g. Vector3) or math libraries. The reason I mention that our game is unique in this way is that its non…

What I agree on is that if we had modern .NET available we'd get a free 2-3x improvement, it would definitely be great. BUT having said that, if you're into performance but unwilling to use the tools available then that's on you. From the article it seems that you're using some form of threading to create things, but you don't really specify which and/or how. The default C# implementations are usually quite poor perf…

Sure, we could use Burst to speed up some strategic parts, but that would not help with the core of the game.

To give some context, things are very complex in our game, we have fully dynamic terrain with terrain physics (land-slides), advanced path-finding of hundreds of vehicles (each entity has its own width and height clearance), trains, conveyors and pipes carrying tens or even hundreds of thousands of individual products, machines, rockets, ships, automated logistics, etc. There is no one thing that could be bursted to get 3x gain. At this point, we'd have to rewrite the entire game in C++.

So what's the reason we use C#? Productivity, ease of debugging and testing, and resilience to bugs (e.g. null dereference won't kill the program). Messing with C++ or even burst would cost us more time and to be honest, the game would possibly not even exist at that point.

Could you share some details about your custom thread pool that got 3x speedup? What was the speedup from? It is highly unlikely that a custom thread pool would have any significant impact on the benchmark in our case. As you can see from Figure 3, threaded tasks run for about 25% of the total time and even with Mono, all tasks are reasonably well balanced between threads. Threads utilization is surely over 90% (there is always slight inefficiency towards the end as threads are finishing up, but that's 100's of ms). An "oracle" thread pool could speed tings up by 10% of 25%, so that is not it.

Vectorization could help too but majority of the code is not easily vectorizable. It's all kinds of workloads, loading data, deserialization, initialization of entities, map generation, precomputation of various things. I highly doubt that automatic vectorization from code generated by IL2CPP would bring more than 20% speedup here. The speedup from burst would mostly come from elimination of inefficient code generated by Mono's JIT, not from vectorization.

For now, we are accepting the Mono tax to be more productive. But I am hoping that Unity will deliver on the CoreCLR dream. In the meantime, my post was meant raise awareness and stir up some discussion, like this one, which is great. I've read lots of interesting thoughts in this comments section.

Re: Unity's Mono problem: C# code runs slower than it should

#174

Earlier quoted context omitted.

> You can also install new DLLs and force the player to restart if you want downloadable mod support. I am not aware of an easy way to load (managed) mods as DLLs to IL2CPP-compiled game. I am thinking about `Assembly.LoadFrom("Mod.dll")`. Can you elaborate how this is done? > there are better, more performant alternatives for that use case, in my experience. We actually use reflection to emit optimal code for generi…

>I am not aware of an easy way to load (managed) mods as DLLs to IL2CPP-compiled game. I am thinking about `Assembly.LoadFrom("Mod.dll")`. Ah, I was thinking native DLLs (which is what we're using on a project I'm working on). I think you're right that it's impossible for an IL2CPP-built player to interoperate with a managed (Mono) DLL. >If you have some suggestions [re: serialization], I'd be interested to see what…

Re serialization: We have custom binary serialization that essentially dumps the game state into a binary stream. No allocations, no copies, no conversions. Our saves can be big, >100 MB uncompressed, so there is no room for waste.

The big advantage is that it reads data directly from game's classes, so there is no boilerplate needed, no prorobufs, no schema. And it supports versioning, adding or removing members mostly without limitations.

I think it's a cool system, maybe I should write a blog post about it :)

Re: Unity's Mono problem: C# code runs slower than it should

#175

Wanted to chime in here with some thoughts/clarifications as I'm the Enginnering Manager of the VM team at Unity, aka the team that is leading the charge on .NET Modernization and the CoreCLR transition (and also owns IL2CPP). Also speaking here as myself and obviously not on behalf of the company. First thing is that CoreCLR is _very_ much an active development effort and we're committed to the roadmap we presented…

Author here, thanks for your comment. I am glad to hear that things are progressing!

Can you share how large is the team responsible for .NET Modernization?

> migrating legacy native C++ code to C# backed by CoreCLR.

Yes please! Surely things like Quaternion.Lerp don't have to be C++ code under CoreCLR.

Feel free to get in touch in case I could be of any help :)

Re: Unity's Mono problem: C# code runs slower than it should

#176
post #95

Earlier quoted context omitted.

I'll add that C# have better performances than gdscript. It doesn't make a difference for most of the things you code in a game, but it comes in handy when needed.

I'd caveat this slightly as "it depends" For mathy stuff, 100% c# is going to be better. But if you need to round trip to the engine a lot getting stuff in and out of the dotnet heap can actually hurt performance. You also have to be _really_ careful because there are a lot of cases you generate accidental garbage (biggest one is when you use strings that are getting implicitly converted to StringNames every time you…

Yes, it tooks me 2 years to see how much garbage strings conversion to String Names generates and how a fool I was calling something like Input.IsActionPressed("move_right") every frame (sadly it's the example given in the input documentation).

Re: Unity's Mono problem: C# code runs slower than it should

#177
post #91

Earlier quoted context omitted.

That last step is nonsensical: WebGPU is a shim layer that Vulkan-like layer (in the sense that WebGL is GLES-like) that allows you to use the native GPGPU-era APIs of your OS. On a "proper OS", your WebGPU is 1:1 translating all calls to Vulkan, and doing so pretty cheaply. On Windows, your browser will be doing this depending on GPU vendor: Nvidia continues to have not amazing Vulkan performance, even in cases wher…

WebGL and WebGPU must robustly defend against malicious web content making the API calls, just like other browser JavaScript APIs, which makes for some overhead and resulted in leaving out some features of the underlying APIs. Vulkan has also evolved a lot and WebGPU doesn't want to require new Vulkan features, lacking for example bindless textures, ray tracing etc.

All APIs must robustly defend against malicious content, this is not something unique to WebGL and WebGPU.

Programs can use Vulkan, D3D, OpenGL, OpenCL, etc, to ex: read memory that isn't in your program's space via the GPU/driver/OS not properly handling pointer provenience. Also, IOMMUs are not always setup correctly, and they are also not bug free, ex: Intel's 8 series.

Using hardware to attack hardware is not new, and not a uniquely web issue.

Re: Unity's Mono problem: C# code runs slower than it should

#178

Earlier quoted context omitted.

WebGPU is far from cheap and has to do a substantial amount of extra work to translate to the underlying API in a safe manner. It's not 1:1 with Vulkan and diverges in a few places. WebGPU uses automatic synchronization and must spend a decent amount of CPU time resolving barriers. You can't just ship a WebGPU implementation in the driver because the last-mile of getting the on screen is handled by the browser in ent…

We already do this by exposing the canvas surface with a semaphore lock. The browser can flip the surface to the canvas (or your app can flip it onto a window surface). It’s just a HINSTANCE pointer. You’re right about the waiting, but that’s entirely app driven. Browsers don’t want to render at 144fps but rather wait until drawing has occurred in order to update the view. wgpu, dawn, already support drawing to arbit…

You've mentioned dawn more than once, but isn't dawn dead since the team at Google that was working on it isn't part of either the Android nor Chrome teams, and Android and Chrome both have their own (and incompatible with each other) preferred API manglers?

Re: Unity's Mono problem: C# code runs slower than it should

#179

Earlier quoted context omitted.

GDScript is not very maintainable as the code base grows. It lacks proper refactoring tools (e.g. the ones from Jetbrains Rider), static type checking, flexible object system and many 3rd party libraries which might be needed

My main point is: if GDScript isn't good enough, go straight to c++ directly in the Engine. I won't even get into how big of projects I've written in GDScript successfully.

I don't want to do manual memory management and pointer handling

I don't want to have any sort of undefined behavior

I want to have quick code reload button in the editor

I want to still rely of the engine official documentation with examples like it is with GDScript and C#

Re: Unity's Mono problem: C# code runs slower than it should

#180
post #91

Earlier quoted context omitted.

WebGL and WebGPU must robustly defend against malicious web content making the API calls, just like other browser JavaScript APIs, which makes for some overhead and resulted in leaving out some features of the underlying APIs. Vulkan has also evolved a lot and WebGPU doesn't want to require new Vulkan features, lacking for example bindless textures, ray tracing etc.

All APIs must robustly defend against malicious content, this is not something unique to WebGL and WebGPU. Programs can use Vulkan, D3D, OpenGL, OpenCL, etc, to ex: read memory that isn't in your program's space via the GPU/driver/OS not properly handling pointer provenience. Also, IOMMUs are not always setup correctly, and they are also not bug free, ex: Intel's 8 series. Using hardware to attack hardware is not new…

> All APIs must robustly defend against malicious content, this is not something unique to WebGL and WebGPU.

This is not the case for C/C++ APIs. A native code application using your API can already execute arbitrary code on your computer, so the library implementing eg OpenGL is not expected to be a security boundary and does not need to defend against for example memory safety bugs to get RCE, info leakage, etc by for example sending in booby trapped pointers or sending in crafted inputs designed to trigger bugs in your API internals.

The kernel side stuff is of course supposed to be more robust but also contains a much smaller amount of code than the user facing graphics API. And robustness there is not taken as seriously because they're not directly internet-facing interfaces so browsers can't rely on correctness any protections there.

Which brings us to: drivers throughout the stack are generally very buggy, and WebGL/WebGPU implementations also have to take responsibility for preventing exploitation of those bugs by web content, sometimes at rather big performance cost.

To see what it's like you might browse https://chromereleases.googleblog.com/ and search for WebGPU and WebGL mentions and bug bounty payouts in the vulnerabilities such as

[$10000.0] [448294721] High CVE-2025-14765 Use after free in WebGPU.

[TBD][443906252] High CVE-2025-12725: Out of bounds write in WebGPU.

[$25000.0] [442444724] High CVE-2025-11205 Heap buffer overflow in WebGPU.

[$15000][1464038] High CVE-2023-4072: Out of bounds read and write in WebGL.

[$TBD][1506923] WebGPU High CVE-2024-0225

etc.

C/C++ memory safety is hard, even when you're the biggest browser vendor trying your hardest to expose C APIs to JS bindings safely.

There were a lot of WebGL vulnerabilities in a constant stream as well earlier, before WebGPU became more lucrative for bug bounties.

Post reply on HN