Poor Canvas window performance in big FSM's

NodeCanvas Forums Support Poor Canvas window performance in big FSM's

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #14800
    erdoal
    Participant

    Hi, I’m having a great time with NodeCanvas, it’s really way above some of the popular alternatives.

    However, as my player controller FSM has grown, Canvas window became slower up to the point of being a bit painful to use. In edit mode, zooming and panning can drop Canvas fps down to 5-10 depending on zoom level; clicking on stuff has a noticeable delay sometimes. There’s about 90 nodes on my Graph and a similar amount of transitions, complex but nothing crazy. My PC is high-end. I plan to have even more nodes and transitions, as if I’m correct, subgraphs cannot be bound yet, and I need to reference scene objects.

    Edit mode Profiler, while panning Canvas, shows that constant serialization is the reason for the slowdown:

    Editmode2
    Editmode1

    Is there a reason why it serializes graph and blackboard every frame? Is it supposed to do so? (it’s possible I accidentally broke something with my small extensions, though unlikely).

    In playmode, serialization doesn’t happen, but still having Canvas open in playmode hits performance too hard to be able to always keep it open (even though my game itself runs fast because it’s 2d), which is sad as playmode features are life savers. Profiled in playmode, those two are the main resource eaters:

    Playmode

    They mostly consist of:

    • Node.NodeWindowGUI — 9.24 ms (40 instances)
    • Connection.DrawConnectionGUI — 8.5 ms (52 instances).

    These boil down to GUI drawing and string manipulation. I’m not experienced at the GUI rendering part; as for strings, it seems that String.Format/Concat are used every frame for labels, headers and info boxes. Maybe there is a way to not do them every frame, but only when the graph is modified?

    As a side note, I suggest adding an option to toggle the minimap. It looks to be a bit taxing as well, and I personally don’t find myself using it even within big graphs.

    Attachments:
    You must be logged in to view attached files.
    #14805
    Gavalakis
    Keymaster

    Hello there,

    Thank you for your detailed report and I am glad you like NodeCanvas ๐Ÿ™‚ Please let me address your questions.

    Serializing is called every frame only if the Graph Asset is selected in the Unity inspector. Basically the Unity inspector is calling OnBeforeSerialize every frame. This is a known issue that I have tried to avoid (with not luck as of yet). The simplest workaround is to please make sure that you have not Graph Asset selected in the Unity inspector.

    There is also a bad GC.Collect call (something that I have removed for the next version already) and which is causing a lot of overhead for no good reason. To remove this call, please open up Graph.cs and in the SelfSerialize method at line #103, please remove the call to System.GC.Collect()

    Node.DrawNodeGUI and Connection.DrawConnectionGUI are methods that basically draw the GUIs for nodes and connections. Please note however that only visible nodes within the canvas are drawn (the rest are not). As such, in max zoom out level where there can potentially be many nodes, it can be taxing, but it shouldn’t be when there aren’t dozens of nodes/connecti0ns shown (or is it? :).

    The minimap can be disabled if you want simply by totally minimizing/scaling it down (at total minimize the minimap will not be shown and the relevant methods will not be drawn as well).

    Having said that, can you please also clarify which version of NodeCanvas you are using?

    Thanks!

    Join us on Discord: https://discord.gg/97q2Rjh

    #14806
    erdoal
    Participant

    Thank you for the quick reply. I’m using the latest v3.03.

    Not having the host GameObject selected helps indeed.

    As of zoom level, it’s better if zoomed in, but still, in playmode my game runs at 200 fps without Canvas window open, and drops down to 50-60 even at max zoom, and 120 if no nodes at all are visible (profiler shows that many of the node/connection drawing methods still get called).

    #14814
    Gavalakis
    Keymaster

    Hello again,

    Hmm. Are you using Deep Profiler by any chance, or does the same slowdown happen with the Profiler closed?

    With that said, in playmode when the graph visible in the graph editor is running, the graph editor is updated per GUI frame (mostly for visual debugging). You can if you want to, please try this:

    – open up GraphEditor.cs and replace line # 540

    from this -> if ( willRepaint || e.type == EventType.MouseMove || rootGraph.isRunning ) {
    to this -> if ( willRepaint || e.type == EventType.MouseMove ) {

    This will avoid repainting the editor per GUI frame, but will also make the visual debugging less “responsive”. Maybe that works for you though ๐Ÿ™‚ Let me know.

    Thanks!

    Join us on Discord: https://discord.gg/97q2Rjh

    #14819
    erdoal
    Participant

    Hmm. Are you using Deep Profiler by any chance, or does the same slowdown happen with the Profiler closed?

    Yes, same happens with the profiler closed.

    This will avoid repainting the editor per GUI frame, but will also make the visual debugging less โ€œresponsiveโ€. Maybe that works for you though Let me know.

    The responsiveness is hurt too much to my liking, though performance problems are completely gone. But you gave me an idea to just make it skip a certain number of OnGUI calls before every Repaint, like this:

    (Left willRepaint || e.type == EventType.MouseMove intact in a separate “if” statement)
    Here I got another problem: repainting every 2nd frame is still a bit taxing; every 3rd frame has almost the same effect as removing rootGraph.isRunning like you suggested. I’m trying to link it to Time.deltaTime but still can’t figure out how to reach that middle ground. The red dots are either lagging very hard or move butter smooth.

    Anyways, skipping every second frame is decent already. Unless you have an idea, I’ll settle on that. Thanks.

    #14831
    Gavalakis
    Keymaster

    Hello again,
    Skipping every 2nd frame is a good midleground solution. Even though I have made a lot of optimizations, I will take a look at what else could be improved there (there always is something ๐Ÿ™‚ )
    Thanks!

    Join us on Discord: https://discord.gg/97q2Rjh

Viewing 6 posts - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.