CLR Performance

by Damon 13. April 2005 05:00
I saw Jacob Cynamon speak at the local .NET user's group last night. He presents well and has a cool name. His topic was general performace tuning for the .net framework. Having gone through an "oh no perforance sucks" experience on a large ASP.NET project and an almost as large compact framework project already this year, this topic was of some interest to me; I wanted to see if I'd missed anything major.

The presentation was good, but it did look like I've hit the major points in my own optimization efforts. I wanted to add my own points to two of Jacob's: the cost of boxing and the cost of throwing exceptions.

Everyone talks about how expensive boxing is as if it's like downloading a 5 meg file over a 14400baud modem. Until last night I had not thought about exactly why boxing is so expensive or how expensive it is compared to other operations. Jacob's initial example showed value type assignment, compared to value type to object and object to value type. The boxing operation took about 13 times as long as assigning a value type. The first impression might be "See, boxing is the devil, we told you so". What could make it so expensive an operation? If I were implementing it I would create a container object to hold the value type and return it when asked. The cost would just be the creation of an object on the heap and maybe a tiny bit of relfection.

After the presentation was over I asked if he could throw a fourth comparison in there: object o = new object();. Sure enough, just calling "new()" took 99% as long as the boxing operation. What's my point? Yes, boxing is expensive compared to just using value types. Run CLR profiler once and see how many objects are created and garbage collected during a mundane operation we take for granted in .NET, like calling a web service. Boxing will be pretty low on my list of things to look for next time I need to squeeze performance out of an application.

The next item I wanted to add to was throwing exceptions. I read a statistic on MSDN somewhere (I can't find the link now) that claimed throwing an exception slowed down the executing thread by a factor of six, or something like that. This makes some sense, in terms of the op codes that would need to be executed to suddenly break execution a lot of things would need to happen: doing a "goto" and running Dispose methods for using and try/finally blocks can't be cheap.

My thought regarding exceptions was similar to my thought on boxing. You should only use exceptions for exceptional situations, not to control program flow. This is not a new tip, I read it first in one of Bjarne Stroustrup's books on the language he invented. Many developers may not be aware of how many exceptions the .NET class libraries are throwing and subsequently swallowing. You'll never see these exceptions unless you run your app in the debugger, and set all CLR exceptions to break into the debugger whether or not they are handled. You might be surprised how many times security violation exceptions are thrown while trying to read resource files, or to know that VB methods like CanParse or IsDate function by just trying to Parse and catching the FormatException if the operation fails. Depending on what functions your app is calling you may be suffering from hundreds or thousands of swallowed exceptions, especially at the time your app starts up. Matt Terski gave another good example in that every time you call Response.Redirect("foo") in ASP.NET a ThreadAbortedException is thrown. Check those First Chance excpetions!

Tags:

Smartphone Impressions

by Damon 11. April 2005 05:00
I've had my Smartphone for a few days and had a chance to mess around with the phone and the WindowsMobile 2003 Smartphone SDK.

I love this thing. Microsoft did a fantastic job on usability for the phone. I can access everything I need with my thumb and no need for typing. There are many little nice thoughts that show the attention to detail that went into this:
  • You can dial or text-message directly from your outlook contacts
  • During a call, the screen shows the person you're talking to. There are buttons on the call screen to pull up your calendar and contact info; if you're on the phone and somoene wants an appointment, you're right there.
  • Wireless sync is easy to set up
  • Performance is much better than I expected

I've actually used the data connection for "real world" things already. For example, I was out with friends Friday and we needed directions to a bar so having Pocket IE pull up Yahoo! yellow pages was useful. The speed of the data connection on the Cingular network is my only complaint so far.

The Smartphone SDK setup was as straightforward as it could be. Obviously there are some challenges to making an app usable on the phone, and I will post later about the multi-screen UI framework I came up with. The first time I ran my test app I got a security warning each time a new assembly was loaded. I need to look into what I need to do to get rid of this, maybe just signing will take care of it. I will say also that I have managed to "crash" the phone once after the compact framework installation. It doesn't seem like managed code should be able to do anything that would force you to reboot your phone to get sound back. Then again, I'm very good at breaking things.

As soon as I think of something useful I will try a connected app with some web services. Perhaps TechEd will give me some good ideas.

Tags:

Smartphone

by Damon 6. April 2005 05:00
My phone has been slowly dying, giving me an excuse to buy a WindowsMobile 2003 smartphone, the Motorola Mpx220. While I can't immediately think of exactly why I need to run connected .NET apps on my phone or what those apps may be, I downloaded the SDK already and wrote a simple app so I'm ready to go. Hopefully I don't regret getting a GSM phone and all that.

I will get back with my Smartphone observations after my number is ported and I've had it for a few days. I will get back to TRAP soon as well, but I am in the process of building a house right now which takes some time. That and actual paying customers have been very distracting lately.

Tags:

carmack on Java

by Damon 29. March 2005 06:00
I don't think I'd be out of line to say that most of the Java community is adamantly anti-Microsoft. Microsoft is a big evil corporation that does Bad Things™ and the .NET platform is inferior because of this.

I used to write Java; it was, at the time, a good career progression from the C++ work I was doing. I still know tons of Java developers and I've even defended Java as having its merits (and taken a beating for it) to some MSFT folks. The sheer childishness of some people on both sides in regards to trashing the other platform is funny sometimes but most often sad. Technology platform may as well join Religion and Politics as things you don't discuss among friends.

Many times, I've tried to tell a friend about a feature of the .NET platform that is so cool it makes me want to break into song, like designer support. After all this feature is very Component Engineering friendly, and should be a big turn-on to the average Java dude. However, their ears are sealed because MSFT made it. Your loss, my friends.

Despite not being a .NET developer John Carmack is my hero. Technology is his life and despite being a huge fan of LINUX and OpenGL and various non-Microsoft platforms he is 100% fair in his statements. You could say he's equally critical of everything. I respect the fact that despite not being a big MSFT fan Carmack uses Visual Studio to develop because he feels it is without compare as a tool for any serious developer.

On his blog, he finally changed to blogging from .plan updates, he recently described his experiences working with Java. He talks about the woefull inadequecies of the platform where performance is concerned and comes right out and says "Write once and run anywhere" is a joke, especially for mobile platforms. Being a bit of a mobile developer myself, I appreciated his comments. Check them out here.

Tags:

CF Message Queue

by Damon 17. March 2005 06:00
Moral of the story: If you're going to write an app with some threading, test with 3 or more threads at least, even if you don't plan on using more than 2. In .NET, you can get away with murder if you only have 2 threads. Problems with your threading code are much more apparent when 4 threads are in contention for the same resource. In this scenario that resource is the UI message loop.

I support a mobile project that synchronizes a great deal of data over the internet (60meg all told) between a Compact Framework windows app and a PHP/PERL/BSD backend. MSFT tools were not an option for the backend, so using RDA Pull commands to get data is out. The syncrhonization is done via web services, essentially the server sends a DataSet friendly format back and it is merged locally. They recently asked if the sync could be made faster. My first reply was "Yeah, if you could tell me which rows are Inserts vs. Updates so I don't have to do a row-by-row merge" but apparently that is not going to happen either. While working on a completely different application and trying to fight through "medicine head" brought on by DayQuil a good idea came to me.

Like many good ideas it was simple and obvious. The current sync process was:
  1. Ask for data
  2. Get DataSet back from server
  3. Process DataTables row by row (very time consuming in SQL CE 2.0)
  4. Ask for more data
Lather, rinse, repeate. I had already threaded out the Sync process so the UI could keep drawing itself during this time, but now it was clear that I could also implement sort of a local Message Queue so each individual bundle of data could be processed Asynchronous to the other thread which was actually pulling the data from the server. So, I came up with a simple class to queue and dequeue messages, came up with classes and interfaces to represent a Queue Work Item and now performance is considerably better. Messages are being processed while the next message is fetched from the server, so the processor on the mobile device and the bandwidth it can suck from the server are both maxed out at all times.

The actual work queue itself is not rocket science either. Here's the code, complete with all my debug nonsense:

using System;

using System.Collections;

using System.Threading;

using OpenNETCF.Windows.Forms;

namespace Mobile.Sync

{

/// <summary>

/// Summary description for SyncWorkItemQueue.

/// </summary>

public class SyncWorkItemQueue

{

private object _syncRoot;

private System.Collections.Queue _queue;

private bool _run;

public const int QUEUE_THRESHOLD = 50;

public const int CATCH_UP_THRESHOLD = 8;

public SyncWorkItemQueue()

{

_syncRoot = new object();

_queue = new Queue();

_run = true;

}

/// <summary>

/// Default to true

/// </summary>

public bool Run

{

get

{

lock(_syncRoot)

{

return _run;

}

}

set

{

lock(_syncRoot)

{

_run = value;

}

ApplicationEx.DoEvents();

}

}

/// <summary>

/// Get the number of SyncWorkItem s in the queue

/// </summary>

public int ItemCount

{

get

{

lock(_syncRoot)

{

return _queue.Count;

}

}

}

/// <summary>

/// (Synchronized) Add an item to the end of the queue

/// </summary>

/// <param name="workItem"></param>

public void AddToQueue(SyncWorkItem workItem)

{

lock(_syncRoot)

{

Console.WriteLine("Adding: " +workItem);

_queue.Enqueue(workItem);

}

ApplicationEx.DoEvents();

}

public void StartProcessing()

{

ThreadStart threadStart = new ThreadStart(StartWork);

Thread workerThread = new Thread(threadStart);

workerThread.Start();

}

protected void StartWork()

{

while(Run)

{

System.Windows.Forms.Application.DoEvents();

if (_queue.Count > 0 )

{

Console.WriteLine("Processing Item, Count=" + _queue.Count);

SyncWorkItem workItem = (SyncWorkItem)_queue.Dequeue();

try

{

workItem.Updater.UpdateTable();

}

catch(Exception ex)

{

Console.WriteLine(ex);

Console.WriteLine("Error processing work item");

Console.WriteLine(workItem.Updater);

ApplicationEx.DoEvents();

}

Console.WriteLine("Processed: " + workItem.Updater);

}

//Allow everything to update

ApplicationEx.DoEvents();

//Now check for greater than threshold amount, to let everything catch up

if (_queue.Count > QUEUE_THRESHOLD)

{

Console.WriteLine("Catching up");

lock(_syncRoot)

{

for(int i = 0; i < CATCH_UP_THRESHOLD; ++i)

{

SyncWorkItem workItem = (SyncWorkItem)_queue.Dequeue();

workItem.Updater.UpdateTable();

Console.WriteLine("CATCH_UP_THRESHOLD item processed, Count=" + _queue.Count);

ApplicationEx.DoEvents();

}

}

ApplicationEx.DoEvents();

}

}

Console.WriteLine("Ending Startwork");

}

}

}


At the end, if there are work items to process, I just do the following to let the sync thread catch up:

while (_syncQueue.ItemCount > 0)

{

Thread.Sleep(10);

}

_syncQueue.Run = false;



From where I'm standing, this is not too hard to do. I did run into a thread race condition while implementing this though. Even so, I still don't know why the average developer/architect is so afraid of using threading. The dreaded thread race issue was actually relatively easy to track down using the debugger: just hit "Pause" and it displayed all my threads and I could clearly see what thread was blocking where. In my case, the issue was sloppy coding. At one point the sync was not on its own thread and it directly updated the UI. When I put it on its own thread I did not change these messages to fire through Control.Invoke(delegate); I got away with it until more threads and were added to the mix, thus my comment about getting away with murder when you have only two threads: Application.DoEvents is often enough to resolve a lockup but not once you get beyond 2 threads.

Tags:

Headphones

by Damon 12. March 2005 06:00
I really like coding with headpones on. Obviously there are phases of a project where human interaction is constant and necessary, but there are also phases of the project where you just need to get some work done. During those times, music is my best friend. From Chopin to Chemlab, music helps me focus somehow.

After many years of loyal service my ancient Sony headphones broke recently. I ended up settling for the Senheiser HD 212 phones shown here. Next week I can get some serious work done now.

The refactorings needed for the TRAP designer are done, as is all the other config coded. The next step is simply to get the Engine and Provider Assemblies generating SQL. Most of the Provider code is already written. I also added Log4N as the logger last night.

The designer writeup is in the works, but its going to take a while. I need to do work on three other projects this weekend.

Tags:

Designer Support

by Damon 8. March 2005 06:00
I have not been idle with the TRAP project. I merely hit a snag this weekend that I have not had time to unsnag. I have been working on the visual interface to creating the mapping files. Given that this is a code-like operation, I decided to use the built in Designer functionality. After all, Microsoft spends billions on usability studies before they release a product, so I'm just going to ride that wave. If they say the PropertyGrid is the best way to edit a set of attributes, then I say use the PropertyGrid.

There's the problem though, "Designer Support",Browsable, EditorBrowsable, PropertyGrid, DesignerSerializationVisibility, CollectionEditor, UITypeEditor, TypeConverter, StandardValuesCollection. Ever use those? Many .NET developers, even the best ones I know (yes far better than me) know little or nothing about what you can do with the built in designer support and designer classes in .NET. There's really three categories of things you can do with all this great stuff.
  1. Create your own visual designer to build something visually. (Like my WYSIWYG Mobile printing code)
  2. Add designer attributes to your code, if you are developing a control that many people will use or that you plan to sell. There are some differences in the designer support for Asp.Net versus WinForms.
  3. Use the built in Designer code to "configure" something within your UI. This is what I am doing with the TRAP UI.
I have shown once or twice a screenshot of some Mapping related class inside a property grid. Big deal, right? Well, as soon as you increase the complexity by only showing some of the properties, or editing collections, or wanting to support a list of acceptible values in a dropdown, or wanting to customize the way the editor looks, or wanting to edit nested properties of types with their own properties, things get somewhat complicated fast. There is also practically no documentation or examples to be found, making this an obscure area of .NET knowledge.

I have most of what I want for designer code working in the TRAP UI now, and that alone could make a pretty decent Designer support tuturial. However, I ran into an issue and the code needs to be cleaned up. On the component diagram I showed a UI assembly and a Types Assembly, where Types is not allowed to depend on another TRAP assembly. Well, once I started adding all of the attributes and custom collections (and there's a lot) needed to give me the designer behavior I want I hit a snag and need to refactor. There is a designer class called StandardValuesCollection that you can create from within a TypeConverter; this class makes it so that if you edit a certain value in the designer you get a ComboBox with your value list in it rather than a TextBox where the user could type anything. Well, by placing all these designer attributes and classes within my Types, I eventually found a dependency on the UI project, in this case it was getting the Project context from my Component Director so I could list the database Tables as StandardValues. I now need to completely clean the types of all this knowledge and create "Designable Types", and use a Decorator pattern or something like it to have designable versions of the types. When that is done I will show some designer code samples.

Tags:

Multi key sort with custom Types

by Damon 7. March 2005 06:00
I often revist my own code experiments when the need arises. This weekend at Deeper in .NET someone asked me about my Sorting Types in Code pattern and if it suppoted multi-key sorts. I said no, but it could. The only weakness is that it only supports Ascending sort order for the "extra" keys beyond the first one. So, if you want to sort your data types in C# code, and you want to produce results ala Order by Property, Property2, Property3 then this should work for you. Suppose you have a Type Foo:

public class Foo

{

private string one;

private string two;

private string three;

public Foo(string f1, string f2, string f3)

{

one = f1;

two = f2;

three = f3;

}

public string F1

{

get{return one;}

set{one = value;}

}

public string F2

{

get{return two;}

set{two = value;}

}

public string F3

{

get{return three;}

set{three = value;}

}

}

Create some instances of type Foo to sort. In order to use the new TypeComparer you need the following code

ArrayList fooz = new ArrayList();

Foo f1 = new Foo("z", "z", "c");

Foo f2 = new Foo("a", "m", "z");

Foo f3 = new Foo("a", "m", "c");

Foo f4 = new Foo("a", "c", "c");

fooz.Add(f1);

fooz.Add(f2);

fooz.Add(f3);

fooz.Add(f4);

string[] names = new string[]{"F1","F2","F3"};

TypeComparer tc = new TypeComparer(names, typeof(Foo));

fooz.Sort(tc);

And last but not least, if you are actually interested in using this, here is the code, only slight modifications from the old TypeComparer:

using System;

using System.Collections;

using System.Reflection;

 

namespace DamonPayne.Trap.Engine

{

          /// <summary>

          /// Make it easy to Sort Custom Types

          /// </summary>

          public class TypeComparer : IComparer

          {

                   private delegate int DoCompare(object x, object y);

                   private DoCompare _compareMethod;

                   private PropertyInfo _propInfo;

                   private Hashtable _methods;

                   private bool _caseSensitive;

                   private string _sortProperty;

                   private bool _multiField;

                   private PropertyInfo[] _propInfos;

                   private DoCompare[] _multiMethods;

                                     

                   public TypeComparer(string propertyName, Type objectType)

                   {

                             _caseSensitive = true;

                             _sortProperty = propertyName;

                             _methods = BuildSortMethods();

                             _propInfo = objectType.GetProperty(_sortProperty);

                             if (null == _propInfo)

                             {

                                      throw new ArgumentException(string.Format("Type {0} does not have a Property '{1}'", new Object[] {objectType.ToString(), propertyName}));

                             }

                             _compareMethod = (DoCompare)_methods[_propInfo.PropertyType];

                             if (null == _compareMethod)

                             {

                                      throw new ArgumentException( string.Format("Type not supported: {0}", _propInfo.PropertyType) );

                             }

                   }

 

                   public TypeComparer(string[] names, Type objectType)

                   {

                             _caseSensitive = true;

                             _multiField = true;

                             _sortProperty = names[0];

                             _methods = BuildSortMethods();

                             _propInfos = new PropertyInfo[names.Length];

                             _multiMethods = new DoCompare[names.Length];

                             for(int i = 0; i < names.Length; ++i)

                             {

                                      _propInfos[i] = objectType.GetProperty(names[i]);

                                      if (null == _propInfos[i])

                                      {

                                                throw new ArgumentException(string.Format("Type {0} does not have a Property '{1}'", new Object[] {objectType.ToString(), names[i]}));

                                      }

                                      _multiMethods[i] = (DoCompare)_methods[_propInfos[i].PropertyType];

                                      if (null == _multiMethods[i])

                                      {

                                                throw new ArgumentException( string.Format("Type not supported: {0}", _propInfo.PropertyType) );

                                      }

                             }

 

                   }

 

                   protected Hashtable BuildSortMethods()

                   {

                             Hashtable ht = new Hashtable();

                             ht.Add(typeof(int), new DoCompare(CompareInt));

                             ht.Add(typeof(double), new DoCompare(CompareDouble));

                             ht.Add(typeof(string), new DoCompare(CompareString));

                             ht.Add(typeof(DateTime), new DoCompare(CompareDate));

                             return ht;

                   }

 

                   public bool CaseSensitive

                   {

                             get{return _caseSensitive;}

                             set{_caseSensitive = value;}

                   }

 

                   protected int CompareInt(object x, object y)

                   {

                             int xInt = (int)x;

                             int yInt = (int)y;

                             return xInt.CompareTo(yInt);

                   }

 

                   protected int CompareDouble(object x, object y)

                   {

                             double xDouble = (double)x;

                             double yDouble = (double)y;

                             return xDouble.CompareTo(yDouble);

                   }

 

                   protected int CompareDate(object x, object y)

                   {

                             DateTime xDate = (DateTime)x;

                             DateTime yDate = (DateTime)y;

                             return xDate.CompareTo(yDate);

                   }

 

                   protected int CompareString(object x, object y)

                   {

                             string xString = (string)x;

                             string yString = (string)y;

                             if (!CaseSensitive)

                             {

                                      xString = xString.ToUpper();

                                      yString = yString.ToUpper();

                             }

                             return xString.CompareTo(yString);

                   }

 

                   #region IComparer Members

 

                   public int Compare(object x, object y)

                   {

                             if (_multiField)

                             {

                                      return MultiKeyCompare(x, y);

                             }

                             object xVal = _propInfo.GetValue(x, null);

                             object yVal = _propInfo.GetValue(y, null);

                            

                             return _compareMethod(xVal, yVal);

                   }

 

                   public int MultiKeyCompare(object x, object y)

                   {

                             int index = 0;

                             object xVal = null;

                             object yVal = null;

                             int comp = 0;

                             while(0 == comp && index < _propInfos.Length)

                             {

                                      xVal = _propInfos[index].GetValue(x, null);

                                      yVal = _propInfos[index].GetValue(y, null);

                                      comp = _multiMethods[index](xVal,yVal);

                                      ++index;

                             }

                             return comp;

                   }

 

                   #endregion

          }

}

Happy coding

Tags:

Choosing an OR mapper

by Damon 3. March 2005 06:00
Well, OR mapping is not as un-popular in the .NET world as I thought it was. Only a week or two after I post my target feature list for trap I run across this article on TheServerSide.Net. It seems like I was barking up the right tree, at least according to this article's author. I have to admit I had not thought about supporting OQL, mostly because I personally didn't find I cared much one way or another when I was using other OR tools.

Tags:

Trap Codegen

by Damon 2. March 2005 06:00
TRAP Typegen More code less talk
Late last night I was working on the TRAP type mapping design and I realized I've reached the point where experimentation and refactoring will do more good than thinking deep thoughts about the design even more. I've decided to take a crawl --> walk --> fly approach, by which I mean the easiest feature will be implemented first, moving up to the most complex features. The simplest feature is a select field1, field2, field3 from table operation, quickly followed by adding the Criteria object to the query. From there, 1:1 relationships, then 1:n relationships, then m:n relationships, then the stored procedure execution path, then some of the relfection emit optimizations, the stored procedure execution path, etc.

I added some simple code generation to the Engine assembly the other day. Reducing tedious data access tasks is the goal of this tool and that includes typing get{} set{} code for properties for classes which closely mirror the database schema a great deal of the time. Why not just use public fields?, you ask, Far less typing. From a Reflection standpoint, Properties and Fields must be treated differently in code, and for TRAP I don't want to create a second execution path for Fields vs. Properties. DataBound UI controls in both WinForms and WebForms are only set up to look for Indexers (dataRow["field"]) and Properties, and this makes a second good reason to use Properties, even if they have no intelligence in them. So, here's a shot of the UI generating custom Types from my database schema, which saves me a lot of typing.
br> Unless you've been under a rock (or are new to MSFT tech) you'll recognize the good ole Northwind database there. I decided to use this for testing and examples, rather than show more than I'm ready to show about my other projects that are going to be using this tool. I find this sort of ironic, since the Northwind database has been used in all of the "DataSets and DataReader are the best!" examples I so despise.

When next I open my yap to rap about TRAP I will show the OR Mapper UI in action and some working code.

Tags:

About the author

Damon Payne is a Microsoft MVP specializing in Smart Client solution architecture. 

INETA Community Speakers Program

Month List

Page List

flickr photostream