#Proper Unity Profiling / Viewing DIsassembly
1 messages · Page 1 of 1 (latest)
I'm actually evaluating a Unity for use in an existing project of mine
I expect I will need to switch to ECS either way, but I wanted to have a "standard unity" baseline to compare to
By the way I ported this pathfinding function over from c++
the exact same c++ function takes 70us takes ~3200us in the unity build version 😵💫
Proper Unity Profiling
Wow, .007 ms? Nice. Do you use any Unity methods?
.007 ms my c++ version (simple dijkstra running on a network of heap allocated road objects)
the unity version which is 10x slower is the same code (priority queue swapped for a c# version) with the roads being gameobjects with scripts attached)
I'm only using unity methods to query the list of roads to iterate them, which should be one call
10x slower is not unexpected as I think the representation in memory for gameobjects is probably too inefficient for my use-case, but I would like to investigate this in detail
I was just going to ask what the "road objects" were. I can see GameObject being a limitation here . . .
What I would like to do, but I believe this is very uncommon and thus unsupported,
is to not even use the profiler at first, but simply to look at the raw running machine code (disassembly) and judge for myself if there is anything obviously inefficient going on, so I can avoid certain functions or language constucts
I asked about Unity methods because any call to the Unity API will be slower . . .
I sometimes did that in c++, usually though the tracy profiler
Yeah, again I was going to port enough of my exisitng c++ simulation code to evaluate what would be needed to achive similar perf in unity as my C++ version
ECS will probably be the answer
ECS is definitely the answer. Using the burst compiler and c# job system will increase perf a lot with high-performance c# . . .
You may be able to further increase the speed without it . . .
Since the code compiles into IL—which then compiles into machine code—you'd only be able look at the IL code using a tool . . .
yes, while C++ compiles directly to machine code, and visual studio allows inspecting the disassebly very conveniently
c# has the IL step and it looks like debugging has the JIT run in some kind of special mode where you can't actually see disassembly
I see; that is nerve-racking . . .
Are you going to try optimizing further before moving to ECS, or jump right in?
I'm going to research C# debugging/profiling a little more
Like I said, I'm somewhat of a c++ expert but don't know a lot about c#
I've written my own c++ engines/frameworks in the past, but I'm trying to see how to create highly efficient games in Unity, as I would like to avoid having to write my own renderer from scratch in the future
while my simulation code is fast, my renderer was never all that great
writing culling/lod, shadow rendering etc. from scratch is hard
Oh Interesting, If I build with IL2Cpp and attach visual studio, I can essentially debug it as if I had written c++
That's great. Does it represent the original C# code compiled to IL, or the actual C++ code generated by IL2CPP?
It's the generated C++ I can step through, which looks like this 😅
Which was a foreach loop in C# originally
I gotta say, that's pretty sweet. I think Rider can only show the original C# code compiled to IL. Being able to read the machine code (or even IL) is handy in itself . . .
I can't seem to any sort of source code info when using Mono backend however, even with a development build, but this is more of a C# issue I think
C# people might be able to help me there
In c++ things are a lot simpler
bascially there are debug/release builds and either you have the pdb+source code or not
if you do you can always understand what c++ code results in what assembly, and profilers can usually help you pinpoint what lines take to most time
Yes, you cannot do this with Mono (as far as I've seen) . . .
I'm surprised devlopment builds run slower
Development: A development build includes debug symbols and enables the Profiler
This does not suggest the code itself would run slower
3,3ms -> 4,0ms
Unity can create a visual studio solution for me, in which I seemingly can build the game
seems like Debug and Release both run slow, but "Master" runs at 3,3ms
Supposedly master is without profiler support, weird that it's actually the profiler that makes my code slower
Using the profiler for any version will accrue a perf hit . . .
Release should run faster than Debug . . .
I currently only have a Time measurement around my method to judge, this method takes around 4ms in debug and release, but 3,3 in master
I might be wrong, but I suspect unlike C++, C# debug builds are not actually much slower, instead they just enable debugging support, while the JIT still generates fast code while you have no debugger attached
I don't understand why profiler support would impact perf of my method though, inside the method there should not really be any profiler stuff happening, unless every unity API call you make is somehow profiled
Proper Unity Profiling / Viewing DIsassembly
It's kind of hard for me to google for this, because I don't know how things are actually called
Why does visual studio let me step through C# (but not view disassembly) when "attaching to Unity"
But when I manually attach VS to the game exe, I can view disassembly but not see any source code despite Unity prodviding the pdb?
Assuming chatgpt isn't lying, I've learning that essentially Unity's Mono is running the C# code, and exposes the IL is some way to visual stuido when it is connected
So in the end it has a protocol for setting breakpoints / querying variables etc
This is why visual studio cannot show you the actual machine code, unsure why it can't show the IL though
I heard that dnspy might allow for IL-based debugging
That's why I mentioned Mono doesn't really work. I don't know the issue myself, but people couldn't get it to work . . .
I assume people just rarely want to analyse machine code, so nobody bothers to support it
dnspy or ILspy are the tools I mentioned (but not specifically by name) where you can look at the decompiled code . . .
This is true. Not too many know how —including myself . . . 😅
I am more interested in understanding the IL to help reduce instructions . . .
Yes, personally I think when you actually spend time seriously optimizing a function (only at the end of the project)
you should probably actually understand what the compiler does with your code, and the best way to do that is to simply try and judge the assembly/IL
profilers are great (tracy is amazing for c++ by the way)
but measuring a method is not useful if you don't know why it's slow
for math heavy code, the instructions would matter
in my project I'm usually limited by memory access it seems
In tracy I can use the sample-based mode to view which instructions are sampled more often
if a memory read is the bottleneck, I would usually see an instruction shortly after the read be the one highlighted
That is very detailed. Hopefully, Unity 6 and beyond will have more or some type of access to this . . .
By the way, in my case GetComponentsInChildren() was the problem, it's just really, really slow
Oh man, I wish I saw your code. That would've been the first thing mentioned . . .
Is there anything else or other Unity API calls that you have?
no worry, I know this stuff is slow
I'm really just trying to understand the profiling workflows
To start off, there is never really a reason to have a GameObject field. Most likely, you need a component from the GameObject, or at least, its Transform . . .
Yep, I could just keep track of my entities using raw C# datastructures, next step is avoid using individual scripts for each gameobject and just use a Manager script
but at some point I might as well just use ECS in the first place