Common Performance Testing Mistakes

At my lab recently we have all been benchmarking our applications. Most of our work has to deal with throughput in distributed applications. A lot of the time I see people making common mistakes when performing tests so I decided to blog about it.

  1. Never test from the same machine, your testing program is taking away significant resources from your application!
  2. Is concurrency being tested (depends on your goals, most likely, YES)
  3. If testing for real world applications, network latency is a HUGE factor in performance and affects applications in many different scenarios, some quick tips are:
    1. Never test using a wireless network unless that is part of your tests!
    2. Make sure you are not hitting your network cap or your packets are being changed by your internet provider
    3. If testing a cloud service, do not test from the same service since there could be no network/connection delay. This can be due to several factors but it could be simply because the test tool might be under the same virtual machine as the application!
    4. If you are using a reverse proxy for spoon feeding, make sure you test with and without it!
  4. Most importantly, calculate performance based on real values instead of approximations. Most of the times approximations are NOT true as they are extrapolated to higher values.

In the web, performance is very important, if you don’t think so, ask Google: http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.html

Marissa started with a story about a user test they did. They asked a group of Google searchers how many search results they wanted to see. Users asked for more, more than the ten results Google normally shows. More is more, they said.

So, Marissa ran an experiment where Google increased the number of search results to thirty. Traffic and revenue from Google searchers in the experimental group dropped by 20%.

Ouch. Why? Why, when users had asked for this, did they seem to hate it?

After a bit of looking, Marissa explained that they found an uncontrolled variable. The page with 10 results took .4 seconds to generate. The page with 30 results took .9 seconds.

Half a second delay caused a 20% drop in traffic. Half a second delay killed user satisfaction.

Testing Code Contracts .NET 4.0

Why use Code Contracts?

By providing pre-compiled code contract interfaces other developers can adhere to signatures and also expected behavior. This is specially important due to the Liskov substitution principle.

Dino Esposito wrote a great article on the topic called Code Contracts Preview: Interfaces.

Testing

To test that all the right contracts are in place a test project can be created.

Testing preconditions is possible by catching the exceptions created by those preconditions.


        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ModelNegativeBlance()
        {
            Account acc = new Account()
            {
                AccountName = "NewAccount",
                //0 or positive is expected
                Balance = -99,
                CreationDate = DateTime.Now

            };
        }

Testing postconditions is a bit tricky because the exceptions raised by postconditions are not meant to be caught. Therefore plain strings have to be used.


    public static class TestHelpers
    {
        public static string ContractExceptionName = "System.Diagnostics.Contracts.__ContractsRuntime+ContractException";

    }
    public class RepositoryTests
    {
        public RepositoryTests()
        {

        }

        [TestMethod]
        public void InsertModelWithNoParitionKeyDueToBadRepository()
        {

            var repo = SetBadRepo();
            Account acc = new Account()
            {
                AccountName = "NewAccount",
                Balance = 0,
                CreationDate = DateTime.Now

            };

            try
            {
                repo.InsertAccount(acc);
            }
            catch (Exception ex)
            {
                Assert.AreEqual(TestHelpers.ContractExceptionName, ex.GetType().FullName);
            }
        }
    }

All your clients should go on a diet

During the last few months my graduate supervisor and I have been doing a lot of demos to the major canadian telecommunications companies. In the demos we show different devices interacting with each other (which is something people love at demos). One of the things we get asked fairly often is: “How long did it take to build each one of these applications?” and our usual answer is about less than a day. This usually shocks people.

How can this be done? Simple, we use thin clients and the cloud (or some robust and scalable servers).  By having outsourced the client logic to the cloud it is possible to build thin clients.  The thin clients just do a few data calls (or get their data pushed into them) to exchange information.

Of course, this requires extra effort at front when building the server logic but it saves A LOT of work later.

Just as a note, in all cases many client side optimizations should not be overlooked. As an example, client side caching is a good thing when possible.

Don’t copy-and-paste code. Don’t use debug driven development!

I see a common copy-and-paste trend specially with junior developers. Many of them just copy-and-paste random internet code into their projects. After a while I ask them about their implementation… very few understand what they copy-and-paste and the implications of that implementation!

I inquired further and it was clear that many used debug driven development to get the copy-and-paste code to work. Debug driven development is basically 90% random changes and 10% thinking. This is a popular trend within .NET developers with visual studio because the IDE is amazing…very little planning is required to get things to work.

After a few weeks of seeing this trend I did the following:

If they asked me a question that I believe is due to copy-and-paste or debug driven development I reply with the following questions

  1. Did you google the problem? (some  of them didn’t google the problem!)
  2. Did you copy and paste code? Is that code giving you the error? If you did copy and paste, what does the code do?
  3. What are 2 different approaches to this implementation and why did you choose this implementation?

After answering the questions above, they were able to solve the problems themselves. That makes them happy and it makes me happy!

LINQ-To-SQL Improving Performance

Linq to SQL is great. I love it because it adds a simple abstraction layer that can greatly speed up building a data access layer.

If not used properly, LINQ to SQL can also create performance issues. Here are my general LINQ to SQL guidelines when I work in projects:


Use the “using” statement when working with a context

This is mostly a general C# programming guideline but there have been several times when I see programmers missing this step. Here is more information from MSDN.

The using statement allows the programmer to specify when objects that use resources should release them. The object provided to the using statement must implement the IDisposable interface. This interface provides the Dispose method, which should release the object’s resources.

using statement can be exited either when the end of the using statement is reached or if an exception is thrown and control leaves the statement block before the end of the statement.

Here is an example:

using (NorthwindDataContext context = new NorthwindDataContext())
{
  //do stuff here
}


Compiled queries

To query something with LINQ to SQL there are several “startup” procedures. This procedures are not too bad when queries are not used too often. If the same query is done several times, its heavy and it is the core of the product then it is VERY important to make it a compiled query.

I will not go into too many details about this because there are several posts about the subject:


Use multiple tiny contexts instead of big bulky ones

Contexts are meant to keep track of the objects in the database. By having small contexts with a single purpose then the burden of tracking is lessen and therefore there is less memory consumption.


Do not keep track of object changes in the database unless its needed

There are two good ways to improve the performance of queries that do not involve concurrency issues:

  1. Optimistic concurrency  = off
  2. Object tracking = off

For object tracking, is super easy to turn off:

context.ObjectTrackingEnabled = false;

Sadly, as  Rick Strahl covers in his blog there are a few things/issues to consider when turning off Object Tracking.


Combine Queries and custom expressions

Combining queries is a good idea when working with databases, just grab what you need and aggregate the data into a POCO model or anonymous type. Finally, if extreme fine control is needed, there is always custom expressions.

TeamCity Agent has unregistered (will upgrade)

Recently I was setting up Teamcity and the build agent kept going down. It was starting and stopping. Sometimes it was “starting…” for a long time.

After doing a bit of research I came across this. The agents would appear only for seconds under team city and then go down as inactive with the message “Agent has unregistered (will upgrade)”. The culprit was my antivirus. Apparently this is a common issue but I have not seen many people blog about it.

Windows Azure Tools for Microsoft Visual Studio 1.2 (June 2010)

I am very happy Microsoft updated the Azure Tools to have full integration with Visual Studio. It is extremely easy to set up, just a few clicks to create a certificate and upload it. The process is all guided and it took me around 30 seconds. After the certificate has been uploaded you can deploy from Visual Studio with a neat status bar.

There are some other neat features like IntelliTrace and others that are now available.

Here is a link to the latest release: Windows Azure Tools for Microsoft Visual Studio 1.2 (June 2010)

Complete control over XML in WCF

Sometimes it is needed to have complete control over how WCF manipulates the data being returned. By default, WCF serializes objects and returns them as XML. Sadly, there is not much control on how to create templates over how objects will be serialized (flat structure, hierarchical, etc). In many cases this does not matter. A few weeks ago I stumbled for the first time when I need 100% control over how the XML was formated and being sent.

To send custom formated XML use the message envelope and not the string datatype. If the envelope is not used, it will add extra meta content.

Here is how it can be done:

public Message GetMessage(string xml)
{
    XmlDocument x = new XmlDocument();

    //This is very important as it will VALIDATE the XML. Saved my butt a few times.
    x.LoadXml(xml);

    XmlElementBodyWriter writer = new XmlElementBodyWriter(x.DocumentElement);

    Message msg = Message.CreateMessage(MessageVersion.None,
                OperationContext.Current.OutgoingMessageHeaders.Action, writer);

    return msg;
}

public class XmlElementBodyWriter : BodyWriter
{
    XmlElement xmlElement;

    public XmlElementBodyWriter(XmlElement xmlElement)
                : base(true)
    {
         this.xmlElement = xmlElement;
    }

    protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
         xmlElement.WriteTo(writer);
    }
 }

Also a little warning, the string passed in should be formated and already encoded in the format you want. This can make a huge difference specially when internationalization is involved.

Value Objects in F#

Value Objects are objects that can be shared across different parts of a program. This can have great benefits in performance. Because  the objects are shared it is very important for value objects to be immutable. If value objects are not immutable then any part of the program can change the values and all the other parts can do calculation with erroneous data.

One of my goals was to make immutable objects in F# to take advantage of parallelization and automatic compiler optimizations:


type City(Name:string, X: float, Y:float) =

member t.Name = Name

member t.X = X

member t.Y = Y

type NeighborCities(city1:string, city2:string) =

member x.fromCity = city1

member x.toCity = city2

Objects created in this manner in F# are immutable. Even when they are accessed in other projects outside their definition, their members are read-only. This was specially helpful on the distributed traveling salesman problem I built last year.