SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
I have a situation where I need to have a lot of independent realtime charts rendered on the screen at the same time. I have put a scichart into a user control and that user control into a list so I can reuse my configuration.
Unfortunately, the behavior I am seeing is that when I have more than 5 charts, the charts stutter really badly. I’m using the SciChartPerformanceOverlay to determine what the FPS is of each of the charts.
I can see that in my 5 chart situation, if my mouse cursor is NOT over the window or NOT moving on the window, each chart has an FPS of ~18 for SciChartSurface and an FPS of >500 for Composition Target. When I start to move the mouse around on top of the window, the SciChartSurface FPS value drops to < 5 and the Composition Target drops to ~300.
I’ve got no mouse events hooked up, I’ve set TryApplyDirectXRenderer to true and it seems to accept it. I’ve double-checked the following values:
Direct3D10CompatibilityHelper.HasDirectX10CapableGpu: True
Direct3D10CompatibilityHelper.HasDirectX10RuntimeInstalled: True
Direct3D10CompatibilityHelper.IsSupportedOperatingSystem: True
Direct3D10CompatibilityHelper.SupportsDirectX10: True
I’m suspending the chart before adding points. Each chart only has 1000 points inside a XyDataSeries<int, double> that is databound to a FastLineRenderableSeries. I’m even using Update instead of Append to try to reuse the same memory, in case that makes a difference.
I’ve played with the MaxFrameRate and nothing seems to help.
My dev machine is a bit old and the graphics card is Intel-based, but I never imagined the performance would get so bad so quickly. I’m hoping there’s something I’m missing here as I’ve read such good things about SciChart.
Please let me know if there’s any advice.
Thanks
Hi Brian,
I took a little bit of time to investigate this today. I’ve just come back off vacation and I’m usually the guy to investigate performance issues, so I do apologise for the delay!
OK what I saw was, immediately I was able to reproduce your performance issue when 10 charts were on the screen. This is on a Surface Pro 4 i7 (not a super powerful machine). With 10 charts the application stuttered and was slow.
I took a look at your code, I was interested to see if you had any modifiers enabled – you do not.
I noticed you are using SciChartPerformanceOverlay to debug performance. In fact, you have one of these for each SciChartSurface (10x when 10 charts are shown). Each SciChartPerformanceOverlay has:
So you don’t have 10 charts, you have 30 charts on the screen in the 10x case. Similarly with 50 charts you have 150 charts because of the extra 2 charts per chart added by the SciChartPerformanceOverlay :0
I discovered when you comment out the SciChartPerformanceOverlay, ironically the performance is smooth. The perf overlay itself seems to be the bottleneck (see attached image).
I’m still investigating and will let you know if I find anything else!
EDIT: Update
After a little more time I profiled the application using JetBrains dotTrace. Sure enough. the SciChartPerformanceOverlay is at fault.
Look how in the profile results below, SciChartPerformanceOverlay is using 14.5% of the total application time, whereas the actual SciChartSurface drawing is using just 0.25%. Basically SciChartPerformanceOverlay is using 60x more CPU resources than the actual charts!
Most of the time is spent setting the TextBlock showing the WPF FPS (That’s the FPS of CompositionTarget.Rendering). So what is likely happening is CompositionTarget.Rendering is firing, causing SciChartPerformanceOverlay to update tens of textblocks, which triggers a layout pass, which triggers CompositionTarget.Rendering, which causes WPF to … (a recursive loop basically…)
Can you try the same thing on your side? Just remove the SciChartPerformanceOverlay. What do you see? Does it work?
Best regards,
Andrew
Hi Brian,
Thanks for getting in touch. We have a similar example called “50-Channel EEG” in the Examples Suite. It renders 50 charts with 1000 points each, updating in real-time. May I ask you to try it? How does the example perform on your PC?
Could you please also tell us how often do you update the chart? How many points per update?
Concerning CursorModifier usage, this will slow down the chart indeed. The CursorModifier performs hit-test at every update, plus shows/hides tooltips and axis lables, which are UI elements. These are quite slow to render. So if you switch them of setting ShowTooltip to False, performance of the CursorModifier should improve.
Please let us know about your findings,
Best regards,
Yuriy
Hi Yuriy,
Thank you for the quick reply!
I took a look at the 50-Channel EEG and am surprised that it performs well on my machine. I’ve reduced the number of charts to 10 and display the SciChartPerformanceOverlay and it says that all 10 charts are performing like champs, updating at 30+ FPS regardless of my mouse movements.
There is one concern, though, and that is the CompositionTarget also seems to be less than 100 FPS which is much lower than I’ve seen in my own app. That being said, the performance seems much better than my own app and I’m at a loss for what exactly I’m doing wrong.
To answer your questions, everything is configurable… but by default:
1. My app updates the chart every 40ms.
2. My chart is holding 5 seconds of data in 1000 points, so 200 points per second. The number of points being updated is calculated based on update timing but is ~8 points per update.
Also, not sure where I should set ShowTooltip = false or find the CursorModifier. I couldn’t find any such code in the EEG example so if it’s off by default, I haven’t turned it on.
I’ve attached a zip file containing a sample app I’m using to try to find the best performance for my situation. It’s been modified a lot for configuration/experimentation so please keep that in mind. Hope it makes sense.
I’ve spent the day trying to glean what the actual difference is between your 50-EEG app and this and not sure what could be the issue. From what I can see, there’s a few differences:
I’ve played with each of these things today and nothing seems to make a difference.
The EEG demo gives me hope that 30FPS for multiple charts is a possibility. Now I just need to figure out how to make that happen. If you could take a look at the attached app and let me know if you seen anything obviously wrong, I’d really appreciate it.
Thanks again for the help!
Hi Andrew,
[PASTED FROM ABOVE DUE TO FORMATTING]
Thanks for your detailed reply. I’ve a few comments.
Just to give an idea of our goals –> our target is to have 48 charts on a single screen (3 charts per unit with a max of 16 units per screen). Each unit updates at ~250pts / second and we’ll show 8 seconds worth of data (ie. ~2000 pts/chart).
Now, about your first point of 3 charts for every chart due to overlay:
First, the overlays that I do have in my sample have the ChartsVisibility property set to Collapsed, so the SciChart surface shouldn’t actually be rendering those, should they? This means for 10 charts, I only have 10 charts rendered, not 30. Of course they are updating the overlay data to get the FPS, but I would hope the collapsed charts do not to affect anything.
Second, even when the whole Overlay is Collapsed, the slowdown occurs. I assume the very existence of the overlays is hooking into the CompositionTarget.Rendering, as you’ve described, even when Collapsed. This, combined with the point above, is making these Overlays expensive.
I did find this question from 2 years ago:
https://www.scichart.com/questions/question/comparing-performance-for-a-fifo-chart-shows-direct3-slowest-and-high-quality-renderer-fastest-1
"We’re still investigating why this is, but we believe there is some contention between the rendering (UI) thread and the appending (DataSeries.Append) thread."
So it’s possible that the overlay is doing DataSeries.Append regardless of if the actual chart is visible or not.
To try to get around this issue but also get an idea of SciChart FPS vs Composition FPS, I tried to add a single SciChartPerformanceOverlay in the code behind and have it attach to only the first ChartControl. Unfortunately, it doesn’t seem to pick up the TargetSurface properly. I can see the CompositionTaget and the Chart Stats (point count) properly, but the SciChartSurface is always infinite.
The code I’m using is this:
private static object _overlaySyncLock = new object();
private static bool _overlayCreated = false;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (!_overlayCreated)
{
lock (_overlaySyncLock)
{
SciChartPerformanceOverlay overlay = new SciChartPerformanceOverlay()
{
ChartsVisibility = Visibility.Collapsed,
TargetSurface = sciChartSurface, // <-- Is this correct?
Margin = new Thickness(4),
Background = Brushes.Black,
Foreground = Brushes.AliceBlue
};
GridForOverlay.Children.Add(overlay); // This is an empty grid that positions the overlay where I'd like
_overlayCreated = true;
}
}
}
Am I doing something wrong here?
Re: Update, it seems like the charts of the overlay are not at fault and it’s actually the TextBlock rendering the FPS. Is there any way to set the update speed of the Overlay? If it updated a few times a second or less, that’d be fine for diagnostics and should remove this bottleneck. A MaxFrameRate like the SciChartSurface might be useful. Just a thought.
Now, all that being said, if I remove the overlays it does improve performance but then if I increase the number of charts, the stuttering does come back. I did find that setting RenderPriority to Normal from Low makes this better, but a comment elsewhere in these forums said Low is better to keep UI snappy. What do you think?
I’m also wondering why it is that the mouse movement is what causes the stuttering at all, even without mouse events or modifiers? Can you shed some light on why the mouse movement is a trigger for stuttering?
Finally, the part that puzzles me most is that when the Overlays are there, the SciChartSurface FPS is much lower than the CompositionTarget. The frame rate is much lower than the expected MaxFrameRate of 30. Is there something else throttling it to less than MaxFrameRate?
Sorry for the long reply. I’m enjoying the ease of SciChart API’s and want to figure out/understand this last performance item.
Thanks for all the help! It’s very insightful!
Brian
Hi again Andrew,
Sorry for the delay in replying but things got busy elsewhere. I haven’t forgotten you! And I definitely agree that chart performance is a complex beast! =)
As an update, I’ve added my own frame counter with the ideas you’ve given and have included that in the sample app I’ve attached to this message.
To see the issue, the settings I’ve enabled seem to work on my PC. When you first push the “Start” button, it should run with SC.FPS > 20. Moving the mouse over the window for an extended period of time brings the FPS down considerably (I’ve seen it as low as 12). As soon as I stop moving the mouse, it goes up above 20 again.
Now, I’ve tried to hook up controls to all the performance-related items I can think of for tweaking. Some of these things seem a bit hacky but seem to work.
Two things I’ve noted are
1. RenderPriority cannot be DataBound. To get around this, I’ve given my VM a reference to the SciChartSurface itself. This seems OK but not 100% (setting to Manual cannot be undone).
In any case, I only mention those as observations in case my app itself is causing some issue.
If you have any questions about the app, please let me know. Otherwise, I’m eager to hear your take on what I’m observing.
Thanks again,
Brian
Hi Brian, I just got around to testing this today. So sorry for the delay … I was able to reproduce your 20 FPS in the provided test app.
OK.
If you REMOVE the MaxFrameRate binding entirely (or set it to null), and set RenderPriority = Normal, I now get >40 FPS. This happens whether I move the mouse or not. The chart appears to render entirely smoothly.
Background: Internally to SciChart there are a few ways we handle the render loop. Setting MaxFrameRate creates a DispatcherTimer with a certain priority (below that of mouse input) and with a timer interval of 1/MaxFrameRate. That means that is the maximum you will get. Its likely you won’t go above it, because if the timer fires and the chart is not ready to draw, you end up waiting momentarily before the next timer event. Similarly once you have set MaxFrameRate, RenderPriority is ignored.
Our advice on use of MaxFrameRate and RenderPriority
I don’t observe any stuttering of the UI Controls (buttons, combo boxes) in your app when RenderPriority is normal, so I say leave it.
Now the question for you is – is that performance enough? Or did you want us to debug it further and see if there are any gains to be made?
Best regards,
Andrew
Please login first to submit.