Pre loader

How to improve Chart initialization speed

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

1
1

Hello,

we are building an application where Charts are created/placed by the user in a form of editor.

We observed that the creation of the first Chart takes between 1 to 3 seconds (depending on the system) but the creation of subsequent Charts takes virtually no time (as it should be).

We assume that the creation of the first Chart involves some kind of time consuming initialization that is later used in the creation of subsequent Charts.

So we have researched if there is a way to do this initialization at the start of our application, so the user is not inconvenienced by a three second waiting time while placing the first Chart.

We discovered the “LoadLibrariesAndLicenseAsync”-function. However, it looks like it has no measurable effect.

Maybe we are using it wrong?

Here is an example code to illustrate the problem in a condensed manner:

Two charts are created and each time the time it takes to create them is measured.

The first creation takes about 1600 milliseconds, the second one only 2.

How can we make both creations only take a few milliseconds?

Thank you.

        // SciChartSurface.SetRuntimeLicenseKey("our key");

         await SciChart.Charting.Visuals.SciChart2DInitializer.LoadLibrariesAndLicenseAsync(
           "our key",
            null); //...does not seem to work

        Stopwatch sw = new Stopwatch(); 
        sw.Restart();//start stopwatch

        //creating the first Scichart with test data:

        SciChartSurface sciChartSurface = new SciChartSurface();

        XyDataSeries<double, double> xyDataSeries = new XyDataSeries<double, double>();
        xyDataSeries.AcceptsUnsortedData = true;
        FastLineRenderableSeries fastLineRenderableSeries = new FastLineRenderableSeries();
        fastLineRenderableSeries.DataSeries = xyDataSeries;
        sciChartSurface.RenderableSeries.Add(fastLineRenderableSeries);

        NumericAxis m_xAxis = new NumericAxis();
        NumericAxis m_yAxis = new NumericAxis();
        m_yAxis.AutoRange = AutoRange.Always;
        sciChartSurface.XAxis = m_xAxis;
        sciChartSurface.YAxis = m_yAxis;

        using (xyDataSeries.SuspendUpdates())
        {
            for (int i = 0; i < 100; i++)
                xyDataSeries.Append(i, Math.Sin(i));
        }

        Screen.Children.Add(sciChartSurface);//add first Scichart to grid
        sciChartSurface.Margin = new Thickness(0, 0, 500, 0);

        MessageBox.Show("time: "+sw.ElapsedMilliseconds); //////////  1610 Mlliseconds
        sw.Restart();//restart stopwatch

        //creating the second Scichart with test data:

        SciChartSurface sciChartSurface2 = new SciChartSurface();

        XyDataSeries<double, double> xyDataSeries2 = new XyDataSeries<double, double>();
        xyDataSeries2.AcceptsUnsortedData = true;
        FastLineRenderableSeries fastLineRenderableSeries2 = new FastLineRenderableSeries();
        fastLineRenderableSeries2.DataSeries = xyDataSeries2;
        sciChartSurface2.RenderableSeries.Add(fastLineRenderableSeries2);

        NumericAxis m_xAxis2 = new NumericAxis();
        NumericAxis m_yAxis2 = new NumericAxis();
        m_yAxis2.AutoRange = AutoRange.Always;
        sciChartSurface2.XAxis = m_xAxis2;
        sciChartSurface2.YAxis = m_yAxis2;

        using (xyDataSeries2.SuspendUpdates())
        {
            for (int i = 0; i < 100; i++)
                xyDataSeries2.Append(i, Math.Sin(i));
        }

        Screen.Children.Add(sciChartSurface2);//add second Scichart to grid
        sciChartSurface2.Margin = new Thickness(500, 0, 0, 0);

        MessageBox.Show("time: "+sw.ElapsedMilliseconds); //////////////////////////// 2 Mlliseconds
Version
v6.6.0.26505
  • You must to post comments
1
0

You’ve already tried LoadLibrariesAndLicenseAsync() – that is covered in the video below and should massively improve startup speed.

Here’s an up to date link to the github project

Related forum questions here
https://www.scichart.com/questions/wpf/new-user-slow-load
https://www.scichart.com/questions/wpf/slow-first-time-startup
https://www.scichart.com/questions/wpf/application-hangs-upon-displaying-chart-for-the-first-time

License loading is one of the biggest components of initial startup. It can be done async while your application loads. After that, SciChart WPF has to instantiate the graphics engine (one-time cost) and initialise control templates of the library (loading BAML/XAML which is slow). Once those are done as you’ve noticed subsequent chart startup is fast.

I’ve tested out our AsyncLicenseLoading application above using v7 of SciChart and profiled it. Here’s the breakdown of timings I see:

  • 300 milliseconds for async license load (can be hidden behind a splash screen)
  • 950 milliseconds for first 2D chart load
  • 2ms for second 2D chart load

So I can confirm numbers similar to yours. I decided to profile it and this is what I see in dotTrace for loading a single chart:

enter image description here

  • 737ms spent in instantiating the chart itself.
  • 400ms of which is finding the optimal GPU adapter.
  • Another 140ms spent creating the first rendersurface (initializes the graphics engine)

enter image description here

So there’s room for improvement here.

Maybe we can allow you to do the detection of GPU adapter earlier in splash screen or even skip it altogether if you provide some flags to say what kind of hardware you have.

I’d recommend doing the same test as me – profiling your application startup. It could be you have something else going on there as well such as data creation or instantiation of other controls that are slowing the application startup down.

Best regards
Andrew

  • You must to post comments
1
0

OK Update: You can move the entire GPU Capability Detection into the async initialization thread with this code. Change this in MainWindow.xaml.cs of the Async License Loading test app.

    private async void MainWindowLoaded(object sender, RoutedEventArgs e)
    {
        // Wait for the license initialization we triggered in App.xaml.cs
        await SciChart2D3DInitializer.Awaiter.ContinueWith(result =>
        {
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            // Important. Turn this off, there's a bug in v7 where we're writing the result to a log file
            VisualXcceleratorEngine.WriteWarningsToOutput = false;
            // Force a GPU Cap test now
            Console.WriteLine("Supports HW Acceleration? " + VisualXcceleratorEngine.SupportsHardwareAcceleration);
            MessageBox.Show("Time to do GPU Cap Test? " + sw.ElapsedMilliseconds);
        });

        // ...

The Console.WriteLine() is irrelevant, we want to call VisualXcceleratorEngine.SupportsHardwareAcceleration async while the application is loading.

This will force the GPU Capability test on startup and shave 50% (400ms) off the first chart startup time.

The remaining time is now initialization of the 3D engine (one time) and other instantiation of the chart. I will talk to the WPF team tomorrow see what else we can do.

Thanks for reporting!

Best regards,
Andrew

  • You must to post comments
1
0

Hello Andrew,

thank you for your help, I did the things you mentioned and achieved moderate success.

My current solution however is quite simple:

I create SciChart-Elements (one instance of everything that is available in the editor) in a separate thread that starts at the beginning of the program.

When the user reaches the part of the application were he can place SciChart-Objects, everything is already loaded und there is no delay.

However, if there is a more elegant solution, I’m all ears.

  • Andrew Burnett-Thompson
    Hi Marc, can you share some code how you’ve done this? I wasn’t aware it was possible to create a SciChartSurface on another thread. I guess if you’re just instantiating them and throwing them away it can force initialise the graphics engine. Still discussing with the team possible improvements here. Much of the one-time initialization cost can be moved to an async operation which occurs when application starts up
  • Marc Vahldieck
    Hello Andrew, I have added my solution as an additional answer. I hope this is sufficient.
  • You must to post comments
0
0

Hello Andrew,

I have put the following code in a function that is called if the “Loaded”-Event of the Main-Window of my WPF application is triggered.

Thread var = new Thread(() =>
            {
                new GraphA();
                new GraphB();
            });      
var.SetApartmentState(ApartmentState.STA);            
var.Start();

The Thread is a System.Threading.Thread, GraphA and GraphB are Classes that inherit from UserControl and implement various SciChart-elements.

In the editor, the User can create instances of GraphA and -B without delay once the above thread has finished.

  • Joeri R
    Hello Mark, thank you for sharing your solution. At the moment, it is pretty much all one can do to improve startup perfromance. However, we are working on providing API that will allow for more control over chart initialization and loading.
  • You must to post comments
Showing 4 results
Your Answer

Please first to submit.

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies