
WPF performance
This discussion was imported from CodePlex
cpuserdi wrote at 2013-07-16 19:38:
I would like to use OxyPlot in a WPF application, but appear to be encountering a performance issue. I have 8 plots in a scroll viewer, ~4 onscreen at a time. The plots are initialized and configured in code. They are updated in real-time with data (maybe
10 points per second each) up to a defined maximum amount. If I swap the type from WPF to WindowsForms using a hosted container, the performance doubles. Let me rephrase: WPF has 100% CPU usage and low UI response, WF has 50% CPU usage and good UI response.
Any idea why the difference in CPU usage/performance? Is there something I'm missing to get better WPF usage? I'm not using bindings; the simple code that works for WF is also used for WPF.
Any idea why the difference in CPU usage/performance? Is there something I'm missing to get better WPF usage? I'm not using bindings; the simple code that works for WF is also used for WPF.
kevdog114 wrote at 2013-07-17 20:23:
I've noticed the same thing. I am displaying different charts in WPF with OxyPlot, and the performance is not great (i.e. panning, zooming, and tracking). Some of the charts have as few as a dozen or two points and aren't updated dynamically. The WinForms
example and the online Silverlight example work perfectly.
everytimer wrote at 2013-07-18 17:44:
I think it's a problem with WPF itself.
cpuserdi wrote at 2013-07-18 17:51:
It might be, but my test tries to use the objects using code rather than XAML/binding. The test application itself is WPF. The difference I'm noticing is in using the WPF version of OxyPlot vs the Windows Forms version hosted in the WPF application.
objo wrote at 2013-07-19 08:32:
Can you profile your application to see if the time is spent in your application, the OxyPlot library or in the WPF core?
I have also noticed that other platforms are performing much better than WPF. It would be interesting to know if there is something that can be improved in the WPF implementation!
I have also noticed that other platforms are performing much better than WPF. It would be interesting to know if there is something that can be improved in the WPF implementation!
cpuserdi wrote at 2013-07-19 14:58:
I have since gone ahead using a hosted WF OxyPlot. Seems I'll need a wrapper around it so that resizing will work properly.
I'll try putting together a test app once I have time and have a better idea how to use SharpDevelop's profiler; couldn't find a better one.
I'll try putting together a test app once I have time and have a better idea how to use SharpDevelop's profiler; couldn't find a better one.
cpuserdi wrote at 2013-07-23 20:38:
Below code is currently set to use OxyPlot.WindowsForms control in a WPF application. Change the XAML to use OxyPlot.WPF for comparison. I was unable to retrieve any insight using either SharpDevelop or SlimTune profilers. Perhaps someone else can make
sense of the data.
XAML:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
xmlns:oxy2="clr-namespace:OxyPlot.WindowsForms;assembly=OxyPlot.WindowsForms"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" WindowState="Maximized">
<!-- Comment/Uncomment the plot variant to use: WPF/WF -->
<!--<oxy:Plot x:Name="MyPlot" />-->
<WindowsFormsHost>
<oxy2:Plot x:Name="MyPlot" />
</WindowsFormsHost>
</Window>
Code behind:using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1 {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
InitPlot();
// initialize plot data points
for(int i = 0; i < TOTAL_AXES; i++) {
_SeriesIndex[i] = 0;
sbyte _DataValue = 0;
for(int j = 0; j < TOTAL_POINTS/2; j++) {
_SeriesData[i].Add(new OxyPlot.DataPoint(_SeriesData[i].Count, _DataValue));
_SeriesData[i].Add(new OxyPlot.DataPoint(_SeriesData[i].Count, -_DataValue));
_DataValue++;
}
}
// set up refresh timer for ~30fps
_PlotRefresh.Interval = new TimeSpan(0, 0, 0, 0, 33);
_PlotRefresh.Tick += new EventHandler(Timer_Tick);
}
private void InitPlot() {
OxyPlot.Series.LineSeries srs = null;
OxyPlot.Axes.LinearAxis axisBottom =
new OxyPlot.Axes.LinearAxis(OxyPlot.Axes.AxisPosition.Bottom);
OxyPlot.Axes.LinearAxis axisLeft = null;
double wfpos = 1.0;
MyPlot.Model = new OxyPlot.PlotModel();
MyPlot.Model.Padding = new OxyPlot.OxyThickness(0);
// single bottom axis
axisBottom.MajorGridlineStyle = OxyPlot.LineStyle.Solid;
axisBottom.MinorGridlineStyle = OxyPlot.LineStyle.Solid;
axisBottom.MinimumPadding = 0;
axisBottom.MaximumPadding = 0;
MyPlot.Model.Axes.Add(axisBottom);
for(int i = 0; i < TOTAL_AXES; i++) {
// initialize each left axis
axisLeft = new OxyPlot.Axes.LinearAxis();
axisLeft.Position = OxyPlot.Axes.AxisPosition.Left;
axisLeft.MajorGridlineStyle = OxyPlot.LineStyle.Solid;
axisLeft.MinorGridlineStyle = OxyPlot.LineStyle.Solid;
axisLeft.Minimum = -128;
axisLeft.Maximum = 127;
axisLeft.MinimumPadding = 0;
axisLeft.MaximumPadding = 0;
axisLeft.EndPosition = wfpos;
wfpos -= ((1.0 / TOTAL_AXES) - 0.01);
axisLeft.StartPosition = wfpos;
wfpos -= 0.01;
axisLeft.Key = "AxisKey" + i.ToString();
MyPlot.Model.Axes.Add(axisLeft);
// initialize each series for the axis
_SeriesData.Add(new List<OxyPlot.IDataPoint>(TOTAL_POINTS));
srs = new OxyPlot.Series.LineSeries();
srs.CanTrackerInterpolatePoints = false;
srs.StrokeThickness = 1;
srs.Points = _SeriesData[i];
srs.YAxisKey = axisLeft.Key;
MyPlot.Model.Series.Add(srs);
}
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
_PlotRefresh.Start();
}
private void Timer_Tick(object sender, EventArgs e) {
// this is meant for use with dynamic data/series, but the effects
// are similar using static data for testing
MyPlot.RefreshPlot(true);
}
private const int TOTAL_AXES = 4;
private const int TOTAL_POINTS = 512;
private List<IList<OxyPlot.IDataPoint>> _SeriesData =
new List<IList<OxyPlot.IDataPoint>>(TOTAL_AXES);
private int[] _SeriesIndex = new int[TOTAL_AXES];
private System.Windows.Threading.DispatcherTimer _PlotRefresh =
new System.Windows.Threading.DispatcherTimer();
}
}
cpuserdi wrote at 2013-07-30 17:13:
Not sure how much help this is, but I have some results from the WPF Performance Suite (part of Windows SDK). It's not very detailed, but it indicates "Rendering Thread" uses 50% CPU time and "Layout" uses 20%. As far as I can tell,
WPF/OxyPlot is using hardware acceleration. RenderingCapabilities.Tier returns 2, which is the highest value indicating support for hardware acceleration. The performance suite also indicates the entire OxyPlot control being frequently marked as "dirty"
and requiring refreshing/rendering. This is probably expected behavior when issuing RefreshPlot(true).
cpuserdi wrote at 2013-07-30 19:57:
(Formatting is lacking, just copy the table into notepad.)
"Top 20" results from SharpDevelop profiler:
"Top 20" results from SharpDevelop profiler:
Name Call Count Time Spent TS (self) TS (per call) TS (self/call)
------------------------------------------------------------------------------------------------------------------------------------
WpfApplication1.App.Main 1 19487.779297ms 26.708881ms 19487.779297ms 26.708881ms
OxyPlot.Wpf.Plot.ArrangeOverride 22 6385.794584ms 0.526685ms 290.263390ms 0.023940ms
OxyPlot.Wpf.Plot.UpdateModelAndVisuals 21 6327.732324ms 3.068244ms 301.320587ms 0.146107ms
OxyPlot.Wpf.Plot.UpdateVisuals 21 5852.759366ms 3.663617ms 278.702827ms 0.174458ms
OxyPlot.PlotModel.Render 21 4932.378369ms 14.397502ms 234.875160ms 0.685595ms
WpfApplication1.MainWindow..ctor 1 3128.988608ms 60.921899ms 3128.988608ms 60.921899ms
OxyPlot.PlotModel.RenderAxes 42 2628.290695ms 0.843887ms 62.578350ms 0.020093ms
OxyPlot.Axes.Axis.Render 210 2627.099862ms 1.284219ms 12.509999ms 0.006115ms
OxyPlot.HorizontalAndVerticalAxisRenderer.Render 210 2625.815643ms 13.369001ms 12.503884ms 0.063662ms
WpfApplication1.MainWindow.InitializeComponent 1 2268.427159ms 1.322134ms 2268.427159ms 1.322134ms
OxyPlot.HorizontalAndVerticalAxisRenderer.RenderMajorItems 105 1827.486131ms 4.793490ms 17.404630ms 0.045652ms
OxyPlot.MathRenderingExtensions.DrawMathText 798 1570.425264ms 1.443802ms 1.967951ms 0.001809ms
OxyPlot.MathRenderingExtensions.DrawMathText 798 1568.981462ms 4.374377ms 1.966142ms 0.005482ms
OxyPlot.Wpf.ShapesRenderContext.DrawText 798 1561.215147ms 11.262844ms 1.956410ms 0.014114ms
OxyPlot.PlotModel.AdjustPlotMargins 21 1155.307446ms 14.229514ms 55.014640ms 0.677596ms
OxyPlot.PlotModel.MaxSizeOfPositionTier 42 1120.887111ms 1.372298ms 26.687788ms 0.032674ms
OxyPlot.Axes.Axis.Measure 105 1119.405653ms 4.064151ms 10.661006ms 0.038706ms
OxyPlot.PlotModel.RenderSeries 21 1091.402684ms 2.620846ms 51.971556ms 0.124802ms
WpfApplication1.App..ctor 1 1088.683889ms 161.166694ms 1088.683889ms 161.166694ms
OxyPlot.Series.LineSeries.Render 84 1087.583511ms 76.632450ms 12.947423ms 0.912291ms
I also have the SharpDevelop profile project file if needed (~20MB).Customer support service by UserEcho