Tech Tock

Time is of the essence.

TranslateTransform vs Canvas Top/Left

Did a little performance testing of Canvas positioning vs TranslateTransform.  Turns out Canvas positioning is almost twice as fast.

Its just a single window with code behind. The asterisks stand in for marker symbols that could show Long/Short/Net/Gross is a custom chart.

image

You can download the code in the PositionPerformance directory of my .Net Demos project on GitHub or below.

 

MainWindow.xaml
  1. <Window x:Class="PositionPerformance.MainWindow"
  2.        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.        Title="MainWindow" Height="350" Width="525">
  5.     <Grid>
  6.         <Grid.ColumnDefinitions>
  7.             <ColumnDefinition Width="*" />
  8.             <ColumnDefinition Width="Auto" />
  9.         </Grid.ColumnDefinitions>
  10.  
  11.         <ListBox ItemsSource="{Binding Data}">
  12.             <ListBox.ItemTemplate>
  13.                 <DataTemplate>
  14.                     <Canvas Width="10" Height="100" >
  15.  
  16.                         <!–<TextBlock Text="*"
  17.                                Canvas.Left="{Binding X}"
  18.                                Canvas.Top="{Binding Y}" />
  19.  
  20.                         <TextBlock Text="*"
  21.                                Canvas.Left="{Binding X1}"
  22.                                Canvas.Top="{Binding Y1}" />
  23.  
  24.                         <TextBlock Text="*"
  25.                                Canvas.Left="{Binding X2}"
  26.                                Canvas.Top="{Binding Y2}" />
  27.  
  28.                         <TextBlock Text="*"
  29.                                Canvas.Left="{Binding X3}"
  30.                                Canvas.Top="{Binding Y3}" />
  31.  
  32.                         <TextBlock Text="*"
  33.                                Canvas.Left="{Binding X4}"
  34.                                Canvas.Top="{Binding Y4}" />–>
  35.  
  36.  
  37.                         <!–<Canvas Width="10" Height="10">–>
  38.                         <TextBlock Text="*">
  39.                                 <TextBlock.RenderTransform>
  40.                                     <TranslateTransform X="{Binding X}" Y="{Binding Y}" />
  41.                                 </TextBlock.RenderTransform>
  42.                             </TextBlock>
  43.                             <TextBlock Text="*">
  44.                                 <TextBlock.RenderTransform>
  45.                                     <TranslateTransform X="{Binding X1}" Y="{Binding Y1}" />
  46.                                 </TextBlock.RenderTransform>
  47.                             </TextBlock>
  48.                             <TextBlock Text="*">
  49.                                 <TextBlock.RenderTransform>
  50.                                     <TranslateTransform X="{Binding X2}" Y="{Binding Y2}" />
  51.                                 </TextBlock.RenderTransform>
  52.                             </TextBlock>
  53.                             <TextBlock Text="*">
  54.                                 <TextBlock.RenderTransform>
  55.                                     <TranslateTransform X="{Binding X3}" Y="{Binding Y3}" />
  56.                                 </TextBlock.RenderTransform>
  57.                             </TextBlock>
  58.                             <TextBlock Text="*">
  59.                                 <TextBlock.RenderTransform>
  60.                                     <TranslateTransform X="{Binding X4}" Y="{Binding Y4}" />
  61.                                 </TextBlock.RenderTransform>
  62.                             </TextBlock>
  63.                             <TextBlock Text="*">
  64.                                 <TextBlock.RenderTransform>
  65.                                     <TranslateTransform X="{Binding X}" Y="{Binding Y}" />
  66.                                 </TextBlock.RenderTransform>
  67.                             </TextBlock>
  68.  
  69.                         <!–</Canvas>–>
  70.                     </Canvas>
  71.                 </DataTemplate>
  72.             </ListBox.ItemTemplate>
  73.             <ListBox.ItemsPanel>
  74.                 <ItemsPanelTemplate>
  75.                     <VirtualizingStackPanel Orientation="Horizontal" />
  76.                 </ItemsPanelTemplate>
  77.             </ListBox.ItemsPanel>
  78.         </ListBox>
  79.  
  80.         <StackPanel Grid.Column="1" Margin="10">
  81.             <Button Click="Button_Click">Run</Button>
  82.             <HeaderedContentControl
  83.                Header="WPF Time"
  84.                Content="{Binding ElapsedMilliseconds}"
  85.                TextBlock.TextAlignment="Right"
  86.                />
  87.             <TextBox x:Name="History" />
  88.         </StackPanel>
  89.     </Grid>
  90. </Window>

MainWindow.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.Collections.ObjectModel;
  15. using System.Diagnostics;
  16.  
  17. namespace PositionPerformance
  18. {
  19.     /// <summary>
  20.     /// longeraction logic for MainWindow.xaml
  21.     /// </summary>
  22.     public partial class MainWindow : Window
  23.     {
  24.  
  25.         public ObservableCollection<Data> Data { get; set; }
  26.         Stopwatch sw = new Stopwatch();
  27.  
  28.         public MainWindow()
  29.         {
  30.             InitializeComponent();
  31.             DataContext = this;
  32.             Data = new ObservableCollection<Data>();
  33.         }
  34.  
  35.  
  36.  
  37.  
  38.         public long ElapsedMilliseconds
  39.         {
  40.             get { return (long)GetValue(ElapsedMillisecondsProperty); }
  41.             set {
  42.                
  43.                 SetValue(ElapsedMillisecondsProperty, value);
  44.  
  45.                 this.History.Text += "\n" + ElapsedMilliseconds.ToString();
  46.             }
  47.         }
  48.  
  49.         // Using a DependencyProperty as the backing store for ElapsedMilliseconds.  This enables animation, styling, binding, etc…
  50.         public static readonly DependencyProperty ElapsedMillisecondsProperty =
  51.             DependencyProperty.Register("ElapsedMilliseconds", typeof(long), typeof(MainWindow), new UIPropertyMetadata(0l));
  52.  
  53.         private void Button_Click(object sender, RoutedEventArgs e)
  54.         {
  55.  
  56.             Data.Clear();
  57.  
  58.             var r = new Random();
  59.  
  60.             foreach (var d in Enumerable.Range(0, 1000).Select(i =>
  61.                 new Data() {
  62.                     X = r.Next(1, 10), Y = r.Next(1, 100),
  63.                     X1 = r.Next(1, 10),
  64.                     Y1 = r.Next(1, 100)
  65.                 ,
  66.                     X2 = r.Next(1, 10),
  67.                     Y2 = r.Next(1, 100)
  68.                 ,
  69.                     X3 = r.Next(1, 10),
  70.                     Y3 = r.Next(1, 100)
  71.                 ,
  72.                     X4 = r.Next(1, 10),
  73.                     Y4 = r.Next(1, 100)
  74.                 }))
  75.             {
  76.                 Data.Add(d);
  77.             }
  78.            
  79.  
  80.             sw.Restart();
  81.  
  82.             Dispatcher.BeginInvoke(new Action(() => ElapsedMilliseconds = sw.ElapsedMilliseconds), System.Windows.Threading.DispatcherPriority.SystemIdle);
  83.  
  84.         }
  85.  
  86.        
  87.  
  88.  
  89.     }
  90.  
  91.     public class Data
  92.     {
  93.         public double X { get; set; }
  94.         public double Y { get; set; }
  95.         public double X1 { get; set; }
  96.         public double Y1 { get; set; }
  97.         public double X2 { get; set; }
  98.         public double Y2 { get; set; }
  99.         public double X3 { get; set; }
  100.         public double Y3 { get; set; }
  101.         public double X4 { get; set; }
  102.         public double Y4 { get; set; }
  103.     }
  104. }

Advertisements

January 21, 2013 Posted by | Uncategorized | , | Leave a comment

Addy Osmani & Mr Monopoly Know jQuery Performance

Fun & informative slides.

image

January 18, 2013 Posted by | Uncategorized | , | Leave a comment

WPF Performance Tip

If you have a lot of controls displaying, layout passes can cause performance issues.  One way to avoid layout passes is to hide rather than collapse elements in converters or triggers. Collapsing an element will cause layout passes while hiding an element will preserve all spacing avoiding the need for a layout pass.

Similarly, frequently changing height and width can be slow in a window with a lot of controls.

If you’re looking to shave off a few hundred extra milliseconds these are worth trying.

January 9, 2013 Posted by | Uncategorized | , | Leave a comment

Quick and Dirty WPF Performance Tester

Here’s a quick way to test WPF performance.  Set some dummy data, then log the the next time the UI thread is available via a Dispatcher.BeginInvoke.  This is a good way to show virtualization is working.  If you need more than this you’re either in high performance land or trouble.

WPF Tester
  1. publicclassViewModel
  2. {
  3.     int_timeTaken;
  4.     publicintWpfTimeTaken
  5.     {
  6.         get { return_timeTaken; }
  7.         set
  8.         {
  9.             CheckPropertyChanged(“WpfTimeTaken”, ref_timeTaken, refvalue);
  10.         }
  11.     }
  12.     privatevoidGenerateData()
  13.     {
  14.         //set data
  15.         varsw = newSystem.Diagnostics.Stopwatch();
  16.         Dispatcher.CurrentDispatcher.BeginInvoke(
  17.             newAction(() =>
  18.             {
  19.                 this.WpfTimeTaken = sw.ElapsedMilliseconds;       
  20.             }), System.Windows.Threading.DispatcherPriority.ApplicationIdle);
  21.     }
  22. }

December 18, 2012 Posted by | Uncategorized | , | Leave a comment

Insanely Cool Video Effects – In WPF!

Here’s a video on Channel 9 from last year showing the incredible things you can do with hardware accelerated graphics in WPF.  I found it totally awesome and was amazed by the incredible performance.

Here’s a textbox on a waving cloth.  I can see somebody doing something with a flag with this effect:

Here’s a 3D window.

I don’t know what the practical applications are in my line of work, but it sure is cool.

The original video includes some more effects that I would describe as more normal video effects such as morphing and color transforms, but with great performance and some extra goodies and it all seems to work with video.

December 4, 2009 Posted by | Uncategorized | , , , | Leave a comment

Charting Update – XCeed Still Going Strong in 3D

I overcame the 3D charting slowness by (duh) changing the point style to inverted pyramid from sphere. Obviously, the graphics hardware (I hope its in hardware) is drawing tons of polygons to show tiny spheres and only a few for pyramids. Why inverted? I don’t really know, but my best guess is that it has to do with lighting and shading, which I’m sure to investigate one day soon. Funny that these tiny dots (up to 22,000 now) are trying to draw themselves in 3D when I can barely see them.

Funny enough, the speed advantage is not apparent on the old MacBook I was planning to demo on.  If I had tried this on the wrong machine, I never would have known it works.

November 12, 2009 Posted by | Uncategorized | , , , , , , , | Leave a comment

Top of the Charts – XCeed is fast

I’m doing an interesting charting project which will plot up to 500 thousand points, so I’m learning a bit about charts.  There seems to be about a million different vendors selling .Net charts, so there’s a lot to choose from.  The problem is there’s about a million different charts, so there’s too many to choose from.  I’ll tell about a couple I’ve used today.

I started with Chart FX, its incredibly feature rich and can do surface charts that we wanted.

chartFX.Surface

Chart FX Surface Chart

Unfortunately, when throwing a few thousand points at it, the performance wasn’t stellar.

I just switched to XCeed.  It can do surface plots too, but its literally a thousand times faster at ploting points.  They say they use GDI, but I think there’s a flux capacitor hidden in there somewhere.  The only downside, is its not WPF, its windows forms.  That doesn’t seem like too much of an issue though.  The XCeed example code is a lot more focused and comprehensive than Chart FX, so far its been a win, but I’m just getting started with it.

xceedSurface

XCeed Chart Surface Chart

The code I uploaded was a big hit, so here’s a quick and dirty app showing that the XCeed chart is 1000 times faster than Chart FX for plotting points:

XceedVsChartFX

XCeed Vs. Chart FX Point Charting Speed

With the same 5000 points given to both charts, XCeed charted in 9 ms and Chart FX took 3.5 seconds.  When resizing the form, Chart FX will freeze up again for 3.5 seconds.  The code is also a good sample of how to use a Windows Forms Control in a WPF application.  Click here for code, with the usual no warranties.

November 7, 2009 Posted by | Uncategorized | , , , , , , , , , , , | 6 Comments

So many quotes — All fake

I was interviewing with an interesting company the other day and I was asked how I would achieve the maximum throughput for a data feed of financial instrument quotes (not just stock quotes, but maybe foreign exchange, or bonds, etc. — its just an example, but I like to generalize :).

So we worked through the problem a little and as always there’s a couple things I left out that I could have said, but I think I did ok. My last statement was — doing it this way will be pretty good, but probably still not good enough.   There’s something in me that just wants to optimize and admitting “not good enough” bugs me.  The next day I was doing normal stuff and an interesting solution struck me out of the blue.  Multithreaded Stacks, enough said.

So I set out to make a demo program to test the theory and lo and behold, you can easily push 50,000 quotes per second through a WPF application!  50K!  On my crappy 2 year old duo 1.66GHZ/T5450.  I couldn’t believe it. Take that AJAX.

It took a while to setup the demo program and I didn’t get to anything I consider innovative or advanced, but I don’t think I’ll be needing any Multithreaded Stacks today.  Just seeing 50,000 quotes flowing through was enough for me.

Here’s the test program:
Mind you its just a demo. The quotes just consist of a random 3 letter id and a random price. But it does have a fun interactive graph thanks to Microsoft and the quotes do update in the grid. Actually all the numbers you can see in the pictures update through the automagic of WPF databinding. I even colored the quote process count with databinding.  This isn’t your daddy’s old Windows Forms, this is W P F.  This actually does more with less effort.  MS may have gotten something right.

The app is all about allowing the user to modify different parameters and combinations that may affect the system.

ThroughputView

On the left side are all the parameter settings. I’ve really just been playing with the Calls Per Second and Quotes Per Call options.  I made 2 quote servers, one in WCF which is a little flaky at higher revs and one that runs a timer to send quotes from the ThreadPool within the application.  I did the WCF first, because it seemed to replicate the problem domain, but its not really germane and I’m moving away from it.

The timer tick, simulates a data push, that I’m calling a “Call”.  Within each data push, the number of quotes requested is sent.  Multiplying “Calls per sec” and “Quotes per call” together gives you the expected quotes that will be pushed at the interface. I say expected, because the implementation of the “quote generator” yields less than the expected amount.

The calls per second can only go so high before it stops increasing the quotes generated number which displays on the bottom statusbar. This is probably because it comes to the resolution limit of the simple System.Timers.Timer I’m using.  In the picture above, its set to 66 calls per second.  Setting it higher does not increase the number of quotes pushed.  Setting the quotes per call higher will increase the throughput and the UI for displaying quotes only gets sluggish over around 60K per second.  CPU usage at 55K quotes per second is only 30 – 40% so maybe I could even do better.

I just put the quote display in a simple ListView/Grid:

DataView

Those quotes are jumpin’ 5 times per second.  Take my word or download the code and see for yourself.

StatusBar

This statusbar shows Snapshot Quotes Per Second (TPS — I use the word Tick and Quote interchangeably — bad habit) at 59,165, Expected Pushed Quotes at 103,563 and Total Processed and Total Served (Pushed) Quotes within 1000 of each other.  Either the consumer is 1/60 of a second behind the producer or just as likely there’s a synchronization issue between those 2 numbers.

You can download the code here and run in Visual Studio or stand alone.  Just hit the Start button to see things go.  Of course the code is AS IS, NO WARRANTY and freely distributable.  See here for additional warnings.

If anybody’s interested I’ll do some more writeups on what’s going on in the code.

September 28, 2009 Posted by | Uncategorized | , , , , , , , , , , , | 3 Comments