ECS System: executed code does not match sourcecode

Hey there,

while trying to debug a system i found that the wrong breakpoints get hit. Trying around with Debug.log i found that the executed code doesnt seem to match the sourcecode.

I created a TestSystem trying to find a minimal example and came to this:

The screnshot also shows code being executed on line 15, while skipping the lines where with the log statements in code.

debug 2
UnityEngine.Debug:Log (object)
TheGame.ecs.TestSystem:OnUpdate (Unity.Entities.SystemState&) (at Assets/Scripts/ecs/TestSystem.cs:15)
...
debug 3
UnityEngine.Debug:Log (object)
TheGame.ecs.TestSystem:OnUpdate (Unity.Entities.SystemState&) (at Assets/Scripts/ecs/TestSystem.cs:17)
...

Rider also shows a notification ā€˜The source file … may have changed since building the module’. But i dont know how to fix the issue and which of my settings might cause the problem.

Can someone explain to me what causes the problems and how i can get rid of them? In my other project i have also been using Assembly files, can those cause issues as well?

edit:
the repo for my example: GitHub - unpiixelbar/ecs_debugging_bug: this unity project is supposed to showcase unintended behaviour in an entity system

When a system method contains a call to SystemAPI, that method will get rewritten into something else. Your OnUpdate becomes a template for that generated method, whose name looks similar to this __OnUpdate_123456. Because your method is a template, it will never run. Only the generated method will run in its place.

That’s why debug breakpoints on your method won’t ever be triggered. What you should do is utilizing Debug.Log as best as you can.

On a side note: SystemAPI methods are actually just empty methods. They do nothing on their own but act as markers for SystemAPI source generator. Behind the scene, this source generator will output actual code that runs at runtime. Both VS and Rider have the ability to inspect generated code.

I understand that the code i write gets used to generate other code, even without burst compilation.
At the same time, i had positive experience using the debugger for ecs a lot of the times (till now) and i also suspect the use of withEntityAccess to cause some problems for debugging my code.

For the already mentioned reasons the Stacktrace of Debug.Log will be useless then, right? Is it possible to debug the generated code?

edit:
This video makes it sound like it should be possible to debug the code.

Getting the debugger line to match the original code from the source generated code being executed is kind of tricky. I mean source generator involving foreach SystemAPI and burst compilations must already be hard as it is.

One thing you can do to improve your debugging expƩrience is to extract your code into a separate method. That way your method is not implicated in the source generation process it just is called by the source generated code.
This makes for a much cleaner debugging experience.

1 Like

Thats a good idea to work around my problem and have some more clean code.

I still feel like something with my code generation is not right. The other day i checked the generated Code and the pragmas, that are supposed to help while debugging, referenced the wrong lines. Like with the wrong stacktraces.
I checked the pragmas again today with Rider and the ā€˜Show generated Code’ Option and this time the pragmas align with the code before generation. The Stacktraces of the logs is still wrong.

If you’re talking about the mismatch in line number then I definitely know the culprit.

You see, in the original code the Debug.Log located at line 36.

But in the generated code, this #line directive makes its own line acts as line 36 so the Debug.Log now located at line 38!

I think if you really need line numbers to match, you should put a bug tag on this post and file a bug report.

1 Like

I’m not sure that’s how it works. #line applies to the next LOC. In your screenshot I think the empty line after #line 36 might be what actually messes things up.

#line lets you modify the compiler’s line numbering and (optionally) the file name output for errors and warnings.

The following example shows how to report two warnings associated with line numbers. The #line 200 directive forces the next line’s number to be 200 (although the default is #6), and until the next #line directive, the filename will be reported as ā€œSpecial.ā€ The #line default directive returns the line numbering to its default numbering, which counts the lines renumbered by the previous directive.

class MainClass
{
    static void Main()
    {
#line 200 "Special"
        int i;
        int j;
#line default
        char c;
        float f;
#line hidden // numbering not affected
        string s;
        double d;
    }
}

I think I encountered this issue before. Sadly, my brain’s memory hole ate the solution if I had one. Maybe check that your file’s EOL characters aren’t messed up?

2 Likes

Yeah my bad, I didn’t double check it. Thanks for pointing out.

See here: Debugging with Rider & Unity DOTS Systems - #2 by Enzi

1 Like

Is there a difference in using lf or crlf on windows, as long as all files use the same EOL?

According to another thread, comments in code break the code gen, so EOL is unrelated after all.

Supposedly it’s fixed in the next Entities release:

I also had problems with code gen in code without comments, like in my example repo. I am excited to see if the problem is gone in the next Entities version.

Guess till then I follow the advice Dani gave in The Hot Path Show Ep. 18

So yeah, it’s working with the exp 1.4.0