Showing posts with label Debug. Show all posts
Showing posts with label Debug. Show all posts

Wednesday, May 13, 2009

How to test your multi-threaded code (part 3 of 3)?

In the last post we learned how to find and fix a simple multi-thread problem. Now we will see a more complex scenario and see how CHESS wil find the solution.

To do that we will add a ne method to our Account type.

public static void Transfer(double amount, Account fromAccount, Account toAccount)
{
    lock (fromAccount)
    {
        lock(toAccount)
        {
            fromAccount.Withdraw(amount);
            toAccount.Deposit(amount);
        }
    }
}

Because we want to be sure that the transfer works we lock both the “from” and the “to” account.

Now we can easily wrtie this test to see that this is working fine in signle threaded scenario.

[TestMethod]
public void TransferTest()
{
    Account a1 = Account.OpenNew(10000);
    Account a2 = Account.OpenNew(10000);

    Account.Transfer(100, a1, a2);
    Account.Transfer(100, a2, a1);

    Assert.AreEqual(10000, a1.Balance);
    Assert.AreEqual(10000, a2.Balance);
}

As we did before we will convert this single-thread method to a multi-thread one.

[TestMethod]
[HostType("Chess")]
public void TransferMultiThreadTest()
{
    Account a1 = Account.OpenNew(10000);
    Account a2 = Account.OpenNew(10000);

    Thread thread = 
new Thread(o => Account.Transfer(100, ((Account[]) o)[0], ((Account[]) o)[1])); thread.Start(new[] {a1, a2}); Account.Transfer(100, a2, a1); thread.Join(); Assert.AreEqual(10000, a1.Balance); Assert.AreEqual(10000, a2.Balance); }

Now if we run this CHESS will detect a deadlock scenario. If you’ve done some SQL queries you know you should always try to lock all your resources always in the same order. But why doesn’t it working here. We have only one method that lock resources they should be locked in the same order every time, and that’s true. The deadlock occurs because in some cases a thread start to lock the fromAccount (or maybe the toAccount too) and get interrupt by another thread trying to do the same. Then both thread are waiting for each other to complete. Databases engine use timeouts to get out of these situation, but the lock keyword doesn’t support timeout, eventough it uses Monitor.Enter which support it. In another post I will show you how to build your own lock implementation that support timeout, but now we need to find a way to make our code thread safe.

We have to go back to our account class and do some changes.

public static object _locObject = new object();

public static void Transfer(double amount, Account fromAccount, Account toAccount)
{
    lock (_locObject)
    {
        fromAccount.Withdraw(amount);
        toAccount.Deposit(amount);
    }
}

We have to create a static lock object we can use to lock on. Because we are doing the lock in one signle operation our test will now run without any problem.

This is only a small overview of what CHESS can do.

Monday, May 11, 2009

How to test your multi-threaded code (part 2 of 3)?

Previously we saw how to build a test to find a multi-thread bug our your code. Now we will look at how to reproduce debug and fix it.

Remember our bank account class:

public class Account
{
   public double Balance { get; set; }

   private Account(double amount)
   {
       Balance = amount;
   }

   public static Account OpenNew(double amount)
   {
       return new Account(amount);
   }

   public void Deposit(double amount)
   {
       double tempAmount = Balance;
       // potential problem
       lock (this)
       {
           Balance = tempAmount + amount;
       }
   }

   public void Withdraw(double amount)
   {
       double tempAmount = Balance;
       // potential problem
       lock (this)
       {
           Balance = tempAmount - amount;
       }
   }
}

And our test:

[TestMethod()]
[HostType("Chess")]
public void BalanceMutiThreadTest()
{
   Account account = Account.OpenNew(10000);

   Thread thread = new Thread(a => ((Account) a).Withdraw(100));
   thread.Start(account);
   account.Deposit(100);
   thread.Join();

   Assert.AreEqual(10000, account.Balance);
}

Now if we look carefully at the test result detail, there is an explanation on how to reproduce this particular schedule. All you have to do is to copy/paste the code provided just before your test method call.

[TestMethod()]
[HostType("Chess")]
[TestProperty("ChessMode", "Repro")]
[TestProperty("ChessBreak", "BeforePreemption")]
#region ChessScheduleString (not human readable)
[TestProperty("ChessScheduleString", @"bpilaiaaaaaaaaaaaeaaonlnahgabmejjgcfcgcpgnmkhlhpekpfeknhoahekbaiiagabdcenijaeabaommbiimnogjcombngjehcdcjklckibmkgffggffnggbgeammonjnlmphnohloplnphnohloplnphlkdljneochphnpppdpfmgggeabgmpgmoeknkmjjocbiakkmibpdphohmbpdpcchomnfpodnhpidfpappfpfhhpponplpkgpmdelpppbgpkplkpoflfmbopdpkgdppbppfpephpocllfpedhppkopjkppjlohpppohpaaldcaoojfhfaaaaaa")]
#endregion
public void BalanceMutiThreadTest()
{
   Account account = Account.OpenNew(10000);

   Thread thread = new Thread(a => ((Account) a).Withdraw(100));
   thread.Start(account);
   account.Deposit(100);
   thread.Join();

   Assert.AreEqual(10000, account.Balance);
}

(your code may be different)

With that code in place if you run your test again (without the debugger) you will see that only one schedule was evaluated and you got the same result as the previous test. From there, as a tester, you job is done. You check in the code and hand it to the development team. If you are a member of a small team, as I usually am, you may be the tester and the developer so you’ll have to debug the code yourself.

Now run this test again but this time with the debugger. The execution should stop just before one of the lock statement. If you step once you will be able to inspect tempAmount and Balance values and see the problem. Between the line where the debugger stop and the previous line another thread changed the Balance value. Now you can see the don’t match.

Of course in this case the solution is easy, we just have to put the tempAmount assignation inside of the lock block but in the next post you will see a case where the solution is not so obvious.

Tuesday, May 5, 2009

How to test your multi-threaded code (part 1 of 3)?

CHESS is the answer. At least this is what we have best right now.

In multi-threaded application, bug are hard to almost impossible to find. For the last years the only true way to detect threading problems was to run load test until the system crash. Once it does, every once in thousands of iterations, the tools to reproduce and debug the problem were inexistent.

The RiSE (Research in Software Engineering) team at Microsoft have been working for a long time on a product called CHESS. When run with CHESS, you unit tests will try every possible combination of thread interleave to find a case where you application crash or worst doesn’t give you the result you expect.

Here is a simple demo to show you the power of CHESS. Let’s start with a banking account management system.

public class Account
{
    public double Balance { get; set; }

    private Account(double amount)
    {
        Balance = amount;
    }

    public static Account OpenNew(double amount)
    {
        return new Account(amount);
    }

    public void Deposit(double amount)
    {
        double tempAmount = Balance;
        // potential problem
        lock (this)
        {
            Balance = tempAmount + amount;
        }
    }

    public void Withdraw(double amount)
    {
        double tempAmount = Balance;
        // potential problem
        lock(this)
        {
            Balance = tempAmount - amount;
        }
    }
}

Of course I voluntarily introduce “potential problems” to show how CHESS will get them. With that class you can write this test:

[TestMethod()]
public void BalanceTest()
{
    Account account = Account.OpenNew(10000);

    account.Withdraw(100);
    account.Deposit(100);

    Assert.AreEqual(10000, account.Balance);
}

This will always run fine as it is single threaded. Now what if we change it a little to make it multi-threaded:

[TestMethod()]
public void BalanceMutiThreadTest()
{
    Account account = Account.OpenNew(10000);

    Thread thread = new Thread(a => ((Account) a).Withdraw(100));
    thread.Start(account);
    account.Deposit(100);
    thread.Join();

    Assert.AreEqual(10000, account.Balance);
}

As you can see here we put the withdraw part in a new thread. But even then we can run this test again and again without any problem. You can put it in a loop if you want and never being able to make it return an invalid balance.

Once you have CHESS installed on your system the only thing you have to do is to add a HostType attribute to your method.

[TestMethod()]
[HostType("Chess")]
public void BalanceMutiThreadTest()
{
    Account account = Account.OpenNew(10000);

    Thread thread = new Thread(a => ((Account) a).Withdraw(100));
    thread.Start(account);
    account.Deposit(100);
    thread.Join();

    Assert.AreEqual(10000, account.Balance);
}

Now when you run this test you should get something like:

Assert.AreEqual failed. Expected:<10000>. Actual:<10100>.

You should also have noticed that it took a little longer to run the test. This is because the CHESS host scans your code to build an execution schedule for every possible thread interleave that CHESS can detect. If you double click on the test result you will see how many schedules that were tried before finding the bug, in my case it is 3.

Next time we will see how to reproduce and debug that code.

Thursday, December 6, 2007

Debugging Windows Service without deploying it

Have you ever tried to build a Windows Service? Did you get it right the first time? Chances are that you had to modify it a couple of time before getting it the way you want it. Each time you had to build the installation package, uninstall the old version and reinstall the new one. Hopfully you can get the installation package to remove old version before installing new one. How did you debug it? Your only option was to start the service and attache a debugger to it. Although this is a good way to do it and you must go to that process before going into production with your service, this is way too much time consuming for the deveopment process. I invite you to take look at a simple class I built to enable any Windows services to be debug from Visual Studio using F5. Here are the step you have to follow:
  1. Build or open your own Windows Service project
  2. Change it's build setting to be a console application
  3. Add ServiceDebuggerHelper project to your solution (can be download from CodeProject)
  4. Add a reference to ServiceDebuggerHelper project in you project
  5. Modify your Program class to start your service with ServiceRunner if it is started with /debug command line argument
  6. Modify your service to be debuggable in one of two way:
    1. Implement IDebuggableService interface
    2. Inherit from DebuggableService base class
  7. Start it in debug mode

See Debugging Windows Service made easy on CodeProject for details.

Wednesday, November 21, 2007

Quick Tip: Knowing if you are running from visual studio or not

I was trying to know if my program is running from visual studio or not. The reason for that is I want to add a pause in my console application only if it runs from visual studio. Otherwise I want it to run normally.

Here is a quick tip I found. I’m not sure if there is another way to do this but this works fine.

if (AppDomain.CurrentDomain.FriendlyName.Contains(".vshost.")) Console.ReadLine();

If you add this line in a console app, it will wait for a enter only if you un it from visual studio.

Thursday, November 1, 2007

Tired of stepping through properties while you debug?

If you are tired of stepping through every properties in your code while you are debugging it here are some cool things you can do



Add a DebuggerHidden attribute.



This attribute applies to Properties, Methods and Constructors. So you can do this:






Add a DebuggerStepThrough attribute.



This attribute applies to Methods, Constructors, Structs and Classes. You can use it on a single property but if you have a simple DO (Data Object) you can mark it so the debugger will step through it.


Of course you can also use the entire assembly in release mode.

Source Download: http://www.docdotnet.com/portal/LinkClick.aspx?link=TestSkipDebug.zip&tabid=129&mid=459


Have fun.