+10
Fixed

Delay in entering play mode

Kingblade 3 years ago updated by Lazlo Bonin (Lead Developer) 2 years ago 21 2 duplicates

Hello there!

I've been using bolt for my project for a while now, and entering play mode has been REALLY slow.
I thought it might be a problem in other things, but right now I was encouraged by a friend to check the problem out on a new project.

So I opened up a new Unity 2018.1.5f1 project, on a new scene. It plays the scene perfectly in less than a second.

But than I tried importing bolt (nothing else, not changing the scene at all) and it now takes about 5-7 seconds. On my main project it takes maybe a tiny bit more.

Are there any known issues on the matter? I've been looking and it seems that everything that mentioned this on the forum was fixed by bolt 1.4 (and for the experiment I used the newest bolt version, 1.4.0f7)

Bolt Version:
Unity Version:
Platform(s):
Scripting Backend:
.NET Version (API Compatibility Level):
Bolt 2

Duplicates 2

I agree! I'm evaluating Bolt for our project at the moment and these are also my main concerns

+1

I tried to remove all assemblies with suffix Editor from folder Assets/Ludiq/Assemblies and improved Editor reloading twice - instead of 16 seconds it takes 8 now. Still not so fast, but much better. I think manual removing of Editor part can be used as temporary workaround.

+1

Thanks for this! I created a menu item to make this easy (use with caution as it's not very well tested!)

using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections.Generic;
using System.Linq;
static public class BoltInstallEditorAssemblies
{
    [MenuItem( "Tools/Install Bolt Assemblies" )]
    static public void InstallBoltAssemblies()
    {
        string allAssembliesPath = Path.Combine( Application.dataPath, "Ludiq/Assemblies" );
        string editorAssembliesStoragePath = Path.Combine( Application.dataPath, "Ludiq/Assemblies/.EditorAssemblies" );
        DirectoryInfo allAssembliesDirInfo = new DirectoryInfo(allAssembliesPath);
        DirectoryInfo editorAssembliesStorageDirInfo = new DirectoryInfo(editorAssembliesStoragePath);
        if ( allAssembliesDirInfo.Exists && editorAssembliesStorageDirInfo.Exists )
        {
            List<string> editorAssemblyFiles = Directory.GetFiles(editorAssembliesStoragePath, "*.*", SearchOption.TopDirectoryOnly).ToList();
            foreach ( string file in editorAssemblyFiles )
            {
                FileInfo fromFileInfo = new FileInfo( file );
                FileInfo toFileInfo = new FileInfo( Path.Combine( allAssembliesPath, fromFileInfo.Name ) );
                if ( !toFileInfo.Exists )
                {
                    //Debug.Log( toFileInfo.FullName );
                    fromFileInfo.MoveTo( toFileInfo.FullName );
                }
            }
        }
        AssetDatabase.Refresh();
    }
    [MenuItem( "Tools/Install Bolt Assemblies", true )]
    static public bool ValidateInstallBoltAssemblies()
    {
        string allAssembliesPath = Path.Combine( Application.dataPath, "Ludiq/Assemblies" );
        string editorAssembliesStoragePath = Path.Combine( Application.dataPath, "Ludiq/Assemblies/.EditorAssemblies" );
        DirectoryInfo allAssembliesDirInfo = new DirectoryInfo(allAssembliesPath);
        DirectoryInfo editorAssembliesStorageDirInfo = new DirectoryInfo(editorAssembliesStoragePath);
        if ( allAssembliesDirInfo.Exists && editorAssembliesStorageDirInfo.Exists )
        {
            List<string> editorAssemblyFiles = Directory.GetFiles(allAssembliesPath, "*Editor*.*", SearchOption.TopDirectoryOnly).ToList();
            if ( editorAssemblyFiles.Count == 0 )
            {
                return true;
            }
        }
        return false;
    }
    [MenuItem( "Tools/Uninstall Bolt Assemblies" )]
    static public void UninstallBoltAssemblies()
    {
        string allAssembliesPath = Path.Combine( Application.dataPath, "Ludiq/Assemblies" );
        string editorAssembliesStoragePath = Path.Combine( Application.dataPath, "Ludiq/Assemblies/.EditorAssemblies" );
        DirectoryInfo allAssembliesDirInfo = new DirectoryInfo(allAssembliesPath);
        DirectoryInfo editorAssembliesStorageDirInfo = new DirectoryInfo(editorAssembliesStoragePath);
        if ( !editorAssembliesStorageDirInfo.Exists )
        {
            editorAssembliesStorageDirInfo.Create();
        }
        if ( allAssembliesDirInfo.Exists )
        {
            List<string> editorAssemblyFiles = Directory.GetFiles(allAssembliesPath, "*Editor*.*", SearchOption.TopDirectoryOnly).ToList();
            foreach ( string file in editorAssemblyFiles )
            {
                FileInfo fromFileInfo = new FileInfo( file );
                FileInfo toFileInfo = new FileInfo( Path.Combine( editorAssembliesStoragePath, fromFileInfo.Name ) );
                fromFileInfo.MoveTo( toFileInfo.FullName );
            }
        }
        AssetDatabase.Refresh();
    }
    [MenuItem( "Tools/Uninstall Bolt Assemblies", true )]
    static public bool ValidateUninstallBoltAssemblies()
    {
        string allAssembliesPath = Path.Combine( Application.dataPath, "Ludiq/Assemblies" );
        DirectoryInfo allAssembliesDirInfo = new DirectoryInfo(allAssembliesPath);
        if ( allAssembliesDirInfo.Exists )
        {
            List<string> editorAssemblyFiles = Directory.GetFiles(allAssembliesPath, "*Editor*.*", SearchOption.TopDirectoryOnly).ToList();
            if ( editorAssemblyFiles.Count > 0 )
            {
                return true;
            }
        }
        return false;
    }
}

Wow, thank you, really usefull!

+1
Working on Fix

Hi Dmitry!

We're aware of the issue and are actively working on strategies to fix it. On most machines, people are seeing a 2-3 second increase, but on slower machines or big codebases, it can be more, like in your case. There are two main culprits right now:

  • FullSerializer, our serialization engine, which is powerful but very slow. Serialization happens when graphs are saved to disk (before entering play mode) and deserialization happens when graphs are loaded from disk (right after entering play mode). We will be switching to Odin Serializer, the serialization engine that powers Odin Inspector by Sirenix, in the near future. We're looking at a ~5x performance boost from that switch alone.
  • I realized recently that some initialization code happens earlier than needs be. For example, all macros will be initialized instantly even if some are not in use by the current scene. This can be fixed with some restructuring of the initialization code, but it's tricky to do it without breaking anything.

The static initializers themselves have already been thoroughly optimized multiple times, but I'm not excluding attempting another round of optim there while looking at the other issues. You seem to have profiled the editor; can you share a screenshot of the deep profiling where most time is spent?

Good news, thank you! We'll be waiting for updates.

I tried to profile Editor again and have no success. Every time I try to collect the data my video card is disabled because of RAM problems. Deep profiling of Editor state changing requires a lot RAM I guess, my machine has only 8 GB. Previously I was lucky and successfully collected data. And now I tried 4 times and always got disabled video card. One of that times I successfully stopped profiling but the card disabled when I moved cursor to that long frame with static initializers. Here is the video what happening when I'm trying to profile: https://youtu.be/eBvs3OPVt4o

I tried a deep profile in 2018.3.0b2, and there's an exception on entering playmode (TypeLoadException: Could not load type 'UnityEditor.PreferencesWindow' from assembly 'UnityEditor). But the profile might still be useful to you...



+2

More profiles! I went back to Unity 2017.4 and a different project to get profiles of before and after adding the Bolt assemblies (no Bolt graphs were created), and also to take profiles of entering play mode and compiling. The slow down for both seem to be caused by the same thing as in the deep profile above, and that is all the work that goes on in ProcessInitializeOnLoadAttributes()

Before Bolt added to project

Entering play mode:


Compile:


After adding Bolt to project

Entering play mode:


Compile:


Pending Review

Hi yulawk! This is our top priority in performance.

The delay you're seeing is basically Bolt initializing. It needs to initialize:

  • After compiling
  • Before entering play mode

We can't keep it initialized across those boundaries, unfortunately, because the entire set of assemblies gets reloaded by Unity. So the only solution is to optimize initialization.

Our plans are:

  • Implement Odin Serializer, which we're estimating will speed up any serialization / deserialization operation by a factor of approximately 5
  • Late-define units to avoid executing initialization code when out of scene. Sounds complicated, but in the end it just means faster loading times.
  • Do another aggressive pass of optimization on the plugin container initializer.

Note that having a graph open or not will not impact the load time.

Okay, awesome! Thats great to hear that you found a way. It is one of my Sprint items to find out if there is a way to make things faster. Do you have an estimate on when those updates would roll out? Sounds like not till the next big release.

I wish I could tell you it'll be soon, but unfortunately I can't. These are pretty major core changes and it'll indeed be in the next major release, with an alpha and beta period before. Sorry!

If it proves impossible to make initialisation fast enough, could you add an option to disable it? Most people in our team don't need to ever use Bolt, but suffer the initialisation delays. The work around of deleting the editor assemblies is nasty but it's what we have to do at the moment.

+1

We have same issue in our project :(. We have a really huge project at this moment and we just switch from PlayMarker to Bolt. Bolt gave us really big freedom and thats nice but  our PlayMode enter time on Empty Scene or any other scene is terrible :(. I will post  some screenshots in few minutes so meybe also our Profiler Data will help you improve that thing.

Edit: Empty scene without bolt  in  our project just run in 1-2 seconds after adding bolt into project this time just increase up to 7-8 seconds

How you can see here we got extra 3.5 sec on empty scene becouse of PluginCotnainer. I sure that PluginContrainer is a part of LUDIQ.






Now take a look on  non empty scene which one contains objects that use bolt flow or state machine :



Lazlo Bonin  are you able to tell us something more about that and meybe help us to reduce that time.


We now use bolt 1.4.0f6



+1

Hi Klasa,

This is all related to what I explained earlier in the thread: serialization with FullSerializer and plugin container initialization.

But the huge spike in your second screenshot makes no sense to me. The serialization/deserialization shouldn't take so long unless you're using embed graphs on the objects you're instantiating. Can you switch these objects to macro graphs and see if you get a boost in performance? It should be major.

+1

Thanks Lazlo for qucik answer ! Sure we will change all of them to macros and I will let you know.

+1

This has been discussed before, and there's a bug listed about Bolt taking a long time when changing play state. The (nasty) workaround is to remove the editor assemblies when you don't actually need to use the Bolt editor. It's something that is being worked on I believe.

https://support.ludiq.io/communities/5/topics/2214-bolt-and-ludiq-both-take-a-lot-of-time-when-editor-changes-state

These are really unfortunate news :(

My workflow relies heavily on using bolt, as it's an easy "scripting language" to script my scenes "actors", so deleting bolt's assemblies will mean even more lost time for me.

Nonetheless, thank you very much for the advice, I hope it will get fixed soon...

+1
Working on Fix

Hi Kingblade! 

Don't worry, we feel your pain. Improving this startup performance is at the core of a lot of our design decisions for Bolt 2. We're aiming for near-instant initialization in the future. Stay tuned!

+1
Fixed in Alpha

This is largely fixed in Bolt 2 Alpha 4 thanks for the new Odin serialization and a ton of optimizations to the plugin container.