I am trying to update the chart in a single core machine at say 10hz. And I see the cpu jumps to 100%. So I tried to insert point efficently as using the RangeObservableClass to insert points to the observable collection tied to chart.
public class AddRangeObservableCollection<T> : ObservableCollection<T>{ private bool _suppressOnCollectionChanged; public void AddRange(IEnumerable<T> items) { if (null == items) { throw new ArgumentNullException("items"); } if (items.Any()) { try { _suppressOnCollectionChanged = true; foreach (var item in items) { Add(item); } } finally { _suppressOnCollectionChanged = false; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (!_suppressOnCollectionChanged) { base.OnCollectionChanged(e); } }}But when I use range to add points seems like it is efficient but, the XAxis does not get updated.??? Why. Is there someway I can optimize this further?Help Help....
The CPU performance story for some of these use cases is something we are hoping to target soon. We have some performance improvements planned for some of the internal datachart overhead you are experiencing in that example. This will help to a degree, but you are also just asking Silverlight to update the rendering of the line many times a second, which, since Silverlight does most rendering in software, is somewhat CPU intensive.
For example, you can run the below sample which simulates updating 3 lines in Silverlight many times a second. You will notice the CPU consumption is significant. You can change the Update Interval slider on the bottom to see how changing how often Silverlight needs to update the visual will affect the cpu usage. The xamDataChart should follow a similar pattern if you change how often you give it new points (how the updates are batched).
This sample (below) is not indicative of how the xamDataChart constructs its lines, but should simulate, in isolation, the amount of work that Silverlight is having to do to keep up with the charts demands based on your usage.
Xaml:
<Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <local:FakeLineChart x:Name="line1" Foreground="Blue" /> <local:FakeLineChart x:Name="line2" Foreground="Red" /> <local:FakeLineChart x:Name="line3" Foreground="Green" /> <StackPanel Orientation="Horizontal" Grid.Row="1"> <TextBlock Text="Update Interval: 0.01 seconds" /> <Slider x:Name="theSlider" Width="200" Minimum="0.01" Value="0.05" Maximum="3.0" ValueChanged="theSlider_ValueChanged"/> <TextBlock Text="3 seconds" /> <TextBlock Text=" Curr: " /> <TextBlock Text="{Binding ElementName=theSlider, Path=Value}" /> </StackPanel> </Grid>
and the code behind:
public partial class MainPage : UserControl { private DispatcherTimer _timer = new DispatcherTimer(); private DispatcherTimer _updateTimer = new DispatcherTimer(); public MainPage() { InitializeComponent(); _timer.Tick += new EventHandler(_timer_Tick); _timer.Interval = TimeSpan.FromSeconds(.05); _timer.Start(); _updateTimer.Tick += new EventHandler(_updateTimer_Tick); _updateTimer.Interval = TimeSpan.FromSeconds(.05); _updateTimer.Start(); } void _updateTimer_Tick(object sender, EventArgs e) { line1.UpdateLine(); line2.UpdateLine(); line3.UpdateLine(); } void _timer_Tick(object sender, EventArgs e) { line1.UpdateData(); line2.UpdateData(); line3.UpdateData(); } private void theSlider_ValueChanged( object sender, RoutedPropertyChangedEventArgs<double> e) { _updateTimer.Interval = TimeSpan.FromSeconds(e.NewValue); } } public class FakeLineChart : ContentControl { private Path _path = new Path(); public FakeLineChart() { _path.StrokeThickness = 1; Content = _path; } private List<double> _data = new List<double>(); public void Update() { UpdateData(); UpdateLine(); } public void UpdateLine() { _path.Stroke = this.Foreground; double width = this.ActualWidth; double height = this.ActualHeight; int index = 0; PointCollection data = new PointCollection(); foreach (var item in _data) { double x = width * ((double)index / (double)_data.Count); double y = height - (height * (item / 40.0)); data.Add(new Point(x,y)); index++; } UpdatePath(data); } private void UpdatePath(PointCollection data) { var geom = new PathGeometry(); var fig = new PathFigure(); var seg = new PolyLineSegment(); seg.Points = data; fig.Segments.Add(seg); geom.Figures.Add(fig); _path.Data = geom; } private static Random _rand = new Random(); private double _curr = 20; public void UpdateData() { if (_rand.NextDouble() < .5) { _curr += _rand.NextDouble() * 3.0; } else { _curr -= _rand.NextDouble() * 3.0; } if (_curr > 40) { _curr = 40; } if (_curr < 0) { _curr = 0; } _data.Add(_curr); while (_data.Count > this.ActualWidth) { _data.RemoveAt(0); } } }
My best recommendation for the current version of the XamDataChart, if you want to reduce the cpu consumption, is to throttle the amount of updates sent to the chart, batching the point additions.
There may also be some additional performance features that we can add that are specific to this kind of sliding window based usage to try and lessen the rendering burden on Silverlight. There are some assumptions that could be leveraged due to the fact that points are only being removed from the front and added to the rear, while the middle remain untouched. If the cpu performance of this type of use case is important to you, I would suggest making a feature request detailing your requirements so that we can accurately gauge the priority of this scenario against other planned work.
-Graham
I've posted an answer to your memory leak thread. I'm looking at the other project to analyze the cpu utilization now.
Hi Graham,
Now this issue. I have submited a simple samplewith memory leak issue.
http://community.infragistics.com/forums/p/45311/247101.aspx#247101.
If you run this with single processor( set affinity to one in task manager). You will see that CPU goes to 100%. I am doing this because the web app I am developing is for a device which runs on lots of existing facility where there exists lots of computers with single core. They all will be accessing this page. And I dont want my app to scream for CPU in those computers. So any help in this. Is there someway I can optimize this to reduce CPU load.
I have attached the sample that I downloaded from your site. I run this sample with one processor at more than 15hz freq and you can see the the CPU just shoots up. So my question is are these charts bound to run more efficient on multicore than singe.
Also, make sure that the itemssource that you are setting on the x axis implements INotifyCollectionChanged, of course.