Welcome to MSDN Blogs Sign in | Join | Help

Tail call optimization

wall

I had posted about tail call and how .NET handles it before. However there was some email exchanges and confusion on internal DLs around it and so I thought I'd try to elaborate more on how .NET goes about handling tail calls

Let’s try to break this down a bit.

a) A piece of C# code contains tail recursion .

static void CountDown(int num)
{
Console.WriteLine("{0} ", num);
if (num > 0)
CountDown(--num);
}

b) The C# compiler does not optimize this and generates a normal recursive call in IL

 IL_000c:  ...
IL_000d:  ...
IL_000e:  sub
IL_000f:  dup
IL_0010:  starg.s num
IL_0012:  call void TailRecursion.Program::CountDown(int32)

c) The Jitter on seeing this call doesn’t optimize it in any way and just inserts a normal call instruction for the platform it targets (call for x86)

However, if any compiler is smart enough to add the tail. recursive IL statement then things change.

a) Scheme code

(define (CountDown n)
    (if (= n 0)
         n
      (CountDown (- n 1))))

b) Hypothetical IronScheme compiler will generate (note for scheme it has to do the optimization)

 IL_000c:  ...
IL_000d:  ...
IL_000e:  sub
  tail.
IL_0023:  call void TailRecursion.Program::CountDown(int32)
IL_0029:  ret

c) Based on which JIT you are using and various other scenarios the JIT now may honour the tail. IL instruction and optimize this with a jmp when generating machine instruction

Please note the may in the very last point and refer to here for some instances where the optimization still might not take place…

Posted by abhinaba | 1 Comments
Filed under: ,

A* Pathfinding algorithm animation screen saver

I'm trying to learn WPF and IMO it is not a simple task. Previously whenever I upgraded my UI technology knowledge it had been easy as it build on a lot of pre-existing concepts. However, WPF is more of a disruptive change.

I decided to write some simple fun application in the effort to learn WPF. Since I cannot write a BabySmash application as Scott Hanselman has already done a awesome job out of it, I decided to code up a simulation of A* path finding algorithm and push it out as a screen saver. The final product looks as follows.

AStar

What it does is that it shows a source, a destination with blockages (wall, mountain?) in between and then uses A* algorithm to find a path in between them. This is the same kind of algorithm that is used in say games like Age of the Empires as workers move around collecting wood and other resources. The algorithm is documented here.

Features

  1. It supports plugging in your own scenes with help of the awesome screen/board designer I blogged about
  2. Comes with a WPF and a console client to show the animation
  3. Algorithm can be played with easily to change or tweak it.
  4. Shows full animation including start, end, obstacle, closed cells, current path being probed and the final path
  5. Multi-screen support. Each screen shows a different board being solved.

Limitations:

Obviously this was more of a quick dirty hobby project and there remains a ton to work on. E.g.

  1. Screen saver preview doesn't work.
  2. Setting dialog is a sham.
  3. The boards do not flip for vertically aligned screens
  4. The XAML data binding is primitive and needs some work
  5. The path can choose diagonally across cell even if it seems to cross over diagonal wall of obstacle.
  6. Mouse move alone doesn't shut down the screen saver. You need to hit a
  7. Many more :)

Download:

Download the final binaries from here. Unzip to a folder, right click on the *.scr and choose Install

Download sources (including VS 2008 sln) from here.

Enjoy.

How Many Types are loaded for Hello World

Fairy princess

<Updated> 

Consider the following super simple C# code

namespace SmartDeviceProject1
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Console.WriteLine("Hello");
        }
    }
}

Can you guess how many managed Type gets loaded to run this? I was doing some profiling the .NET Compact Framework loader (for entirely unrelated reason) and was surprised by the list that got dumped. 87 177 types**, never could've guessed that...

  1. System.Object
  2. System.ValueType
  3. System.Enum
  4. System.Void
  5. System.Boolean
  6. System.Char
  7. System.SByte
  8. System.Byte
  9. System.Int16
  10. System.UInt16
  11. System.Int32
  12. System.UInt32
  13. System.Int64
  14. System.UInt64
  15. System.Single
  16. System.Double
  17. System.String
  18. System.Type
  19. System.Reflection.MemberInfo
  20. System.RuntimeType
  21. System.Array
  22. System.IntPtr
  23. System.UIntPtr
  24. System.Text.StringBuilder
  25. System.Delegate
  26. System.MulticastDelegate
  27. System.DateTime
  28. System.Exception
  29. System.MarshalByRefObject
  30. System.AppDomain
  31. System.__ComObject
  32. System.Decimal
  33. System.SZArrayHelper
  34. System.Collections.IEnumerable
  35. System.Collections.IEnumerator
  36. System.Nullable`1
  37. System.SystemException
  38. System.Security.VerificationException
  39. System.Runtime.InteropServices.CurrencyWrapper
  40. System.Runtime.InteropServices.UnknownWrapper
  41. System.Runtime.InteropServices.DispatchWrapper
  42. System.Runtime.InteropServices.ErrorWrapper
  43. System.Runtime.InteropServices.CustomMarshalerHelper
  44. System.Attribute
  45. System.Runtime.InteropServices.InterfaceTypeAttribute
  46. System.Runtime.InteropServices.GuidAttribute
  47. System.Runtime.InteropServices.ComVisibleAttribute
  48. System.Runtime.InteropServices.ComEventInterfaceAttribute
  49. System.Runtime.InteropServices.ComSourceInterfacesAttribute
  50. System.Runtime.InteropServices.LCIDConversionAttribute
  51. System.Runtime.InteropServices.ComDefaultInterfaceAttribute
  52. System.Runtime.InteropServices.DispIdAttribute
  53. System.CorPubObject
  54. System.Char[]
  55. System.Collections.Hashtable
  56. System.Reflection.BindingFlags
  57. System.Reflection.MemberFilter
  58. System.Reflection.Binder
  59. System.Type[]
  60. System.Reflection.TypeAttributes
  61. System.Void*
  62. System.Int32[]
  63. System.IntPtr[]
  64. System.Collections.IDictionary
  65. System.UnhandledExceptionEventHandler
  66. System.AppDomainManager
  67. System.Version
  68. System.Runtime.InteropServices.ComInterfaceType
  69. System.Collections.ICollection
  70. System.Collections.IEqualityComparer
  71. System.AppDomainManagerInitializationOptions
  72. System.ArithmeticException
  73. System.ArgumentException
  74. System.MissingMemberException
  75. System.MemberAccessException
  76. System.AppDomainSetup
  77. System.Runtime.InteropServices.Marshal
  78. System.PInvoke.EE
  79. System.Reflection.AssemblyName
  80. System.Byte[]
  81. System.Globalization.CultureInfo
  82. System.Reflection.Assembly
  83. System.Configuration.Assemblies.AssemblyHashAlgorithm
  84. System.Configuration.Assemblies.AssemblyVersionCompatibility
  85. System.Reflection.AssemblyNameFlags
  86. System.Globalization.CultureTableRecord
  87. System.Globalization.CompareInfo
  88. System.Globalization.TextInfo
  89. System.Globalization.NumberFormatInfo
  90. System.Globalization.DateTimeFormatInfo
  91. System.Globalization.Calendar
  92. System.Globalization.BaseInfoTable
  93. System.Globalization.CultureTable
  94. System.Globalization.CultureTableData
  95. System.Globalization.CultureTableData*
  96. System.UInt16*
  97. System.Globalization.NumberStyles
  98. System.Globalization.DateTimeStyles
  99. System.String[]
  100. System.Globalization.DateTimeFormatFlags
  101. System.Globalization.TokenHashValue
  102. System.Globalization.TokenHashValue[]
  103. System.Byte*
  104. System.Globalization.CultureTableHeader
  105. System.Globalization.CultureTableHeader*
  106. System.Globalization.CultureNameOffsetItem
  107. System.Globalization.CultureNameOffsetItem*
  108. System.Globalization.RegionNameOffsetItem
  109. System.Globalization.RegionNameOffsetItem*
  110. System.Globalization.IDOffsetItem
  111. System.Globalization.IDOffsetItem*
  112. System.TokenType
  113. System.Int32&
  114. System.IO.TextReader
  115. System.IO.TextWriter
  116. System.IFormatProvider
  117. System.Console
  118. System.Char&
  119. System.Char*
  120. System.ArgumentNullException
  121. System.PInvoke.NSLIntl
  122. System.ArgumentOutOfRangeException
  123. System.RuntimeTypeHandle
  124. System.NotSupportedException
  125. System.PlatformNotSupportedException
  126. System.String&
  127. System.TypeLoadException
  128. System.Globalization.EndianessHeader
  129. System.Globalization.EndianessHeader*
  130. System.Globalization.GlobalizationAssembly
  131. System.BCLDebug
  132. System.PInvoke.TableData
  133. System.InvalidProgramException
  134. System.Collections.HashHelpers
  135. System.Globalization.CultureTableItem
  136. System.UInt32&
  137. System.Security.CodeAccessSecurityEngine
  138. System.LocalDataStoreMgr
  139. System.Threading.ExecutionContext
  140. System.LocalDataStore
  141. System.Collections.ArrayList
  142. System.Threading.SynchronizationContext
  143. System.Runtime.Remoting.Messaging.LogicalCallContext
  144. System.Runtime.Remoting.Messaging.IllogicalCallContext
  145. System.Threading.Thread
  146. System.Object[]
  147. System.Collections.Generic.Dictionary`2
  148. System.Runtime.Remoting.Messaging.CallContextRemotingData
  149. System.Runtime.Remoting.Messaging.CallContextSecurityData
  150. System.Collections.Generic.IEqualityComparer`1
  151. System.InvalidOperationException
  152. System.Globalization.CultureTableRecord[]
  153. System.Threading.Monitor
  154. System.Globalization.CultureTableRecord&
  155. System.Object&
  156. System.Threading.Interlocked
  157. System.Runtime.CompilerServices.RuntimeHelpers
  158. System.RuntimeFieldHandle
  159. System.PInvoke.PAL
  160. System.IndexOutOfRangeException
  161. System.IntPtr&
  162. System.Buffer
  163. System.NullReferenceException
  164. System.OutOfMemoryException
  165. System.InvalidCastException
  166. System.OverflowException
  167. System.DivideByZeroException
  168. System.ArrayTypeMismatchException
  169. System.MissingMethodException
  170. System.FormatException
  171. System.RankException
  172. System.Security.SecurityException
  173. System.StackOverflowException
  174. System.Threading.ThreadAbortException
  175. System.Threading.ThreadTerminateException
  176. System.MethodAccessException
  177. SmartDeviceProject1.Program

**This is for the compact framework CLR. Your mileage will vary if you run the same on the desktop CLR.

Designer for my path finding boards

I'm writing a small application (or rather a screen saver) that animates and demonstrates A* search algorithm. The idea is simple. On screen you see a start and end point and some random obstacles in between them. Then you see animation on how A* algorithm is used to navigate around the board to find a path (close to the shortest possible) between the two.

All of this is fairly standard. However, I got hit by a simple issue. I wanted to have the ability to design this board visually and also let my potential million users do the same. Obviously I don't have time to code up a designer and hence choose the all time manager's favorite technique. Re-use :)

So the final solution I took was to use Microsoft Office Excel as the WYSIWYG editor. I created a xlsx file with the following conditional formatting which colors cells based on the value of the cells.

Excel Conditional Formatting screen shot for blog

So in this case

  1. w = Wall marking the end of the table
  2. b = blocks/bricks/obstacle
  3. s = start
  4. e = end

Using this I can easily design the board. The designer in action looks as follows

Excel Designer For A* blog screenshot

Since the excel sheet has conditional formatting the user just types in s, e, b, w in the cells and they all light up visually. At the end he/she just saves the file using File => Save As and uses CSV format. This saves the file shown above as

w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w
w,,,,,,,,,,,,,,,,,,,,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,b,,,,,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,s,,,,,,,,b,b,b,b,b,b,,,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,,b,b,b,b,,b,b,b,b,,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,b,b,b,,,,,,b,b,b,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,b,b,,,,,,,,b,b,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,b,b,,,,,,,,b,b,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,b,b,,,,,,,b,b,,,,,b,,,,,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,b,b,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,b,b,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,b,b,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,b,b,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,b,,,,b,,,,,,,,,,,e,,,w
w,,,,,,,,,,,,,,,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,b,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,,,,,b,,,,,,,,,,,,,,w
w,,,,,,,,,,,,,,,,,,,,,,,,,,,b,,,,,,,,,,,,,,w
w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w

As you see the format is simply a row per line and every column separated by a comma. My simulator reads this file and renders using whatever renderer is configured (console or WPF).

More about the A* simulator to come soon...

It's is easy to claim that the world won't get destroyed today

Taken inside the Microsoft Campus Hyderabad

The clock is ticking and the Large Hadron Collider in Cern is going to get switched on today (9/10/2008). Even though there are speculations, CERN is claiming it's perfectly safe and the world won't end. But it's easy to claim that, who'll be around to prove them wrong in case they are :)

It's one of the coolest device at an operating temperature of < -270°C. But I'd get really angry if there's any disturbance to my Birthday celebrations!!

Posted by abhinaba | 3 Comments

Team Foundation Server tool dump workspace details

Bangalore airport

I juggle around with a lot of workspaces. The reason is .NET Compact Framework is consumed in a whole bunch of things like Windows Mobile, Xbox, Zune, Nokia and most of them are on different source branches. On top of this active feature work happens in feature branches and there are other service branches to frequently peek into.

So the net effect is I need to sometime go to different folders and see what it's source control workspace mapping is or I need to dump details of workspaces on other computers and see if I can use that workspace as a template to create a new workspace.

The thing I hate here is to run cd to that folder and do a tf workspace to bring up the GUI and then dismiss the UI. I don't like GUI when things can be done equally well on the console. So I quickly hacked up a tool that dumps workspace details onto the console, something as below

d:\>workspace.exe NETCF\F01
Name:      ABHINAB2_S60
Server:    TfsServer01
Owner:     Abhinaba
Computer:  ABHINAB2

Comment:

Working folders:

Active   $/NetCF/F01/tools     d:\NETCF\F01\tools
Active   $/NetCF/F01/source    d:\NETCF\F01\source


-

This tool can be used either to see the mapping of a folder or given a workspace name and owner dump it details. It uses the exact same format as show in the tf workspace UI.

Source

The source and a build binary is linked below. It is a single source file (Program.cs) and you should be able to pull it into any version of Visual Studio and even build it from the command line using CSC

  1. Source
  2. Binary

Using the tool

Build it or use the pre-built binary and edit the .config file to point it to your TFS server and you are all set to go.
Posted by abhinaba | 1 Comments

Obsession with desktop continues

Desktop

This is my new office setup. I have been pushing around a lot of code lately and felt I needed more real-estate to effectively do what I'm doing. So I hooked up another monitor. All  3 are standard HP LP1965 19" monitors.

However, since none of my video cards support 3 monitors and I have a whole bunch of computers to hook up I had to do some complex wiring around :). If I number the screens 1,2,3 from left to right this is how it works out

  • 1 and 2 is connected to my main dev box (machine1)
  • 2 and 3 is connected to the machine I use for emails and browsing (machine 2)
  • 2 actually goes through a 4-port KVM switch using which it can circle through machine1, machine2 and two other less used machines
  • 1 also goes through a 2 port KVM switch and connects a xbox and machine 1
  • I don't use the laptop at work directly, I connect to it using remote desktop.

Sweet :)

It's not as complex as it sounds. For my normal flow I just use the KVM to switch between machine-1 and machine-2. I rarely need to switch between the xbox and machine1.

PS: Don't try to make much sense of the Vintage books on the shelve, I plan to keep them for some more time before handing them off to some historian.

Posted by abhinaba | 4 Comments
Filed under: ,

Back to Basic: Using a System.Threading.Interlocked is a great idea

Bound to give you diabetes :)

I just saw some code which actually takes a lock to do a simple set operation. This is bad because taking locks are expensive and there is an easy alternative. The System.Threading.Interlocked class and its members can get the same job done and much faster.

I wrote the following two methods which increments a variable a million times. The first method does that by taking a lock and the other uses the Interlocked.Increment API.

static int IncrementorLock()
{
    int val = 0;
    object lockObject = new object();
    for (int i = 0; i < 1000000; ++i)
    {
        lock (lockObject)
        {
            val++;
        }
    }

    return val;
}

static int IncrementorInterlocked()
{
    int val = 0;
    for (int i = 0; i < 1000000; ++i)
    {
        System.Threading.Interlocked.Increment(ref val);
    }

    return val;
}

 

I then used the Visual Studio Team System Profiler (instrumented profiling) and got the following performance data.

Function Name Elapsed Inclusive Time Application Inclusive Time
LockedIncrement.Program.IncrementorInterlocked() 1,363.45 134.43
LockedIncrement.Program.IncrementorLock() 4,374.23 388.69

Even though this is a micro benchmark and uses a completely skewed scenario, it still drives the simple point that using the interlocked class is way faster.

The reason the interlocked version is faster is because instead of using .NET locks it directly calls Win32 apis like InterlockedIncrement which ensures atomic updation to variables at the OS scheduler level.

These Interlocked APIs complete depend on the support of the underlying OS. This is the reason you'd see that all the APIs are not available uniformly across all versions of .NET (e.g. there is no uniform coverage over WinCE and Xbox). While implementing these for the Nokia platform (S60) we are hitting some scenarios where there is no corresponding OS API.

String equality

Flowers At the Botanical park

akutz has one of the most detailed post on string interning and equality comparison performance metrics I have ever seen. Head over to the post here

I loved his conclusion which is the crux of the whole story.

"In conclusion, the String class’s static Equals method is the most efficient way to compare two string literals and the String class’s instance Equals method is the most efficient way to compare two runtime strings. The kicker is that there must be 10^5 (100,000) string comparisons taking place before one method starts becoming more efficient than the next. Until then, use whichever method floats your boat."

Posted by abhinaba | 1 Comments

Writing exception handlers as separate methods may prove to be a good idea

Flowers At the Botanical park

Let us consider a scenario where you catch some exception and in the exception handler do some costly operation. You can write that code in either of the following ways

Method-1 : Separate method call

public class Program
{
    public static void Main(string[] args)
    {
        try
        {
            using (DataStore ds = new DataStore())
            {
                // ...
            }
        }
        catch (Exception ex)
        {
            ErrorReporter(ex);
        }
    }

    private static void ErrorReporter(Exception ex)
    {
        string path = System.IO.Path.GetTempFileName();
        ErrorDumper ed = new ErrorDumper(path, ex);
        ed.WriteError();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(path);
        RemoteErrorReporter er = new RemoteErrorReporter(xmlDoc);
        er.ReportError();
    }
}

-

Method-2 : Inline

public static void Main(string[] args)
{
    try
    {
        using (DataStore ds = new DataStore())
        {
            // ...
        }
    }
    catch (Exception ex)
    {
        string path = System.IO.Path.GetTempFileName();
        ErrorDumper ed = new ErrorDumper(path, ex);
        ed.WriteError();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(path);
        RemoteErrorReporter er = new RemoteErrorReporter(xmlDoc);
        er.ReportError();
    }
}

-

The simple difference is that in the first case the exception handler is written as a separate method and in the second case it is placed directly inline inside the handler itself.

The question is which is better in terms of performance?

In case you do have significant code and type reference in the handler and you expect the exception to be thrown rarely in an application execution then the Method-1 is going to be more performant.

The reason is that just before executing a method the whole method gets jitted. The jitted code contains stubs to the other method's it will call but it doesn't do a recursive jitting. This means when Main gets called it gets jitted but the method ErrorReporter is still not jitted. So in case the exception is never fired all the code inside ErrorReporter never gets Jitted. This might prove to be significant saving in terms of time and space if the handling code is complex and refers to type not already referenced.

However, if the code is inline then the moment Main gets jitted all the code inside the catch block gets jitted. This is expensive not only because it leads to Jitting of code that is never executed but also because all types referenced in the catch block is also resolved resulting in loading a bunch of dlls after searching though the disk. In our example above System.Xml.dll and the other dll containing remote error reporting gets loaded even though they will never be used. Since disk access, loading assemblies and type resolution are slow, the simple change can prove to give some saving.

Microsoft Roundtable

Our conference rooms have been fitted with this really weird looking device (click to enlarge).

I had no clue what the thing was. Fortunately it's box was still placed in the room along with the manual. It's called the Microsoft RoundTable and it is actually a 360-degree camera (with 5 cameras and 6 microphones). It comes with bundled software that let's all participant be visible to the other side in a live meeting at real time. It shows the white board and the software is intelligent enough to focus on and track the active speaker (using microphone and face recognition) and much much more (lot of MS Research stuff has gone into it). The video below gives you some idea and head on to this post for some review and inside view of the device.

Simply put it's AWSOME

Posted by abhinaba | 2 Comments
Filed under: , ,

Do namespace using directives affect Assembly Loading?

Hyderabad Microsoft Campus

The simple answer is no, the inquisitive reader can read on :)

Close to 2 year back I had posted about the two styles of coding using directives as follows

Style 1

namespace MyNameSpace
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    // ...
}

-

Style 2

using System;
using System.Collections.Generic;
using System.Text;
namespace MyNameSpace { // ... }

-

and outlined the benefits of the first style (using directives inside the namespace). This post is not to re-iterate them.

This post to figure out if either of the styles have any bearing in the loading order of assemblies. Obviously at the first look it clearly indicates that is shouldn't, but this has caused some back and forth discussions over the web.

Scot Hanselman posted about a statement on the Microsoft Style cop blog which states

"When using directives are declared outside of a namespace, the .Net Framework will load all assemblies referenced by these using statements at the same time that the referencing assembly is loaded.

However, placing the using statements within a namespace element allows the framework to lazy load the referenced assemblies at runtime. In some cases, if the referencing code is not actually executed, the framework can avoid having to load one or more of the referenced assemblies completely. This follows general best practice rule about lazy loading for performance.

Note, this is subject to change as the .Net Framework evolves, and there are subtle differences between the various versions of the framework."

This just doesn't sound right because using directives have no bearing to assembly loading.

Hanselman did a simple experiment with the following code

using System;  
using System.Xml;  
  
namespace Microsoft.Sample  
{  
   public class Program  
   {  
      public static void Main(string[] args)  
      {  
         Guid g = Guid.NewGuid();  
         Console.WriteLine("Before XML usage");  
         Console.ReadLine();  
         Foo();  
         Console.WriteLine("After XML usage");  
         Console.ReadLine();  
      }  
  
      public static void Foo()  
      {  
         XmlDocument x = new XmlDocument();  
      }  
   }  
}  

-

and then he watched the loading time using process explorer and then he moved the using inside the namespace and did the same. Both loaded the System.Xml.dll after he hit enter on the console clearly indicating that for both the cases they got lazy loaded.

Let me try to give a step by step rundown of how the whole type look up of XmlDocument happens in .NETCF which in turn would throw light on whether using directives have bearing on assembly loading.

  1. When Main method is Jitted and ran the System.Xml.dll is not yet loaded
  2. When method Foo is called the execution engine (referred to as EE) tries to JIT the method. As documented the Jitter only JITs methods that are to be executed.
  3. The Jitter tries to see if the method Foo is managed (could be native as well due to mixed mode support) and then tries to see if it's already Jitted (by a previous call), since it's not it goes ahead with jitting it
  4. The jitter validates a bunch of stuff like whether the class on which the method Foo is being called (in this case Microsoft.Sample.Program) is valid, been initialized, stack requirements, etc...
  5. Then it tries to resolve the local variables of the method. It waits to resolve the local variable type reference till this point so that it is able to save time and memory by not Jitting/loading types that are referenced by methods that are never executed
  6. Then it tries to resolve the type of the variable which in this case if System.Xml.XmlDocument.
  7. It sees if it's already in the cache, that is if that type is already loaded
  8. Since it's not the case it tries to search for the reference based on the type reference information
  9. This information contains the full type reference including the assembly name, which in this case is System.Xml.dll and also version information,strong name information, etc...
  10. All of the above information along with other information like the executing application's path is passed to the assembly loader to load the assembly
  11. The usual assembly search sequence is used to look for the assembly and then it is loaded and the type reference subsequently gets resolved

If you see the above steps there is in no way a dependency of assembly loading on using directive. Hence at least on .NETCF whether you put the using outside or inside the namespace you'd get the referenced assemblies loaded exactly at the time of first reference of a type from that assembly (the step #5 above is the key).

Auto generating Code Review Email for TFS

Hyderabad Microsoft Campus

We use a small command line tool called crmail to auto-generate code review email from shelveset. I find the whole process very helpful and thought I'd share the process and the tool (which has some really cool features).

Features

  1. Automatic generation of the email from the shelveset details
  2. Hyperlinks are put to TFS webaccess so that you can review code from machines without any tools installed, even without source enlistment. Yes it's true!!! The only thing you need is your office's intranet access
  3. You can even use a Windows mobile phone :) and even some non MS browsers. Ok I guess I have sold this enuf
  4. This is how the email looks like with all the details pointed out
    crmail
  5. Effectively you can see the file diff, history, blame (annotate), shelveset details, associated bugs, everything from your browser and best thing is that all of these takes one click each.
    This is how the fill diff looks in the browser
    webdiff

Pre-reqs

  1. Team System Web Access (TSWA) 2008 power tool installed on your TFS server. For the shelveset link to work you'd need TSWA SP1 CTP. The other features work with the base TSWA 2008 install...
  2. Outlook installed on the machine on which the email is generated
  3. Enlistment and TFS client installed on the machine on which the email is generated
  4. For reviewers there is no pre-req other than a browser and email reader.

Dev process

  1. The developer creates a shelveset after he is done with his changes. He ensures he fills up all the details including the reviewers email address ; separated
  2. He runs the tool with a simple command
    crmail shelvesetname
  3. Email gets generated and opened he fills in additional information and fires send
  4. Done!!

Reviewers

Ok they just click on the email links. Since mostly these are managers what more do you expect out of them? Real devs will stick with firing up tfpt command line :)

Configuring the tool

  1. Download the binaries from here
  2. Unzip. Open the crmail.exe.config file and modify the values in it to point to your tfsserver and your code review distribution list (if you do not have one then make it empty)
  3. Checkin to some tools folder in your source control so that everyone in your team has access to it

Support

Self help is the best help :), download the sources from here and enjoy. Buck Hodges post on the direct link URLs would help you in case you want to modify the sources to do more.

How does the .NET CF handle null reference

Hyderabad Microsoft Campus

What happens when we have code as bellow

class B
{
    public virtual void Virt(){
        Console.WriteLine("Base::Virt");
    }
}

class Program
{
    static void Main(string[] args){
        B b = null;
        b.Virt(); // throws System.NullReferenceException
    }
}

Obviously we have a null reference exception being thrown. If you see the IL the call looks like

    L_0000: nop 
    L_0001: ldnull 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: callvirt instance void ConsoleApplication1.B::Virt()
    L_0009: nop 
    L_000a: ret 

So in effect you'd expect the jitter to generate the following kind of code (in processor instruction)

if (b == null)
   throw new NullReferenceException
else
   b->Virt() // actually call safely using the this pointer

However, generating null checks for every call is going to lead to code bloat. So to work around this on some platforms (e.g. .NETCF on WinCE 6.0 and above) it uses the following approach

  1. Hook up native access violation exception (WinCE 6.0 supports this) to a method in the execution engine (EE)
  2. Do not generate any null checking and directly generate calls through references
  3. In case the reference is null then a native AV (access violation is raised as invalid 0 address is accessed) and the hook method is called
  4. At this point the EE checks to see if the source of the access violation (native code) is inside Jitted code block. If yes it creates the managed NullRefenceException and propagates it up the call chain.
  5. If it's outside then obviously it's either CLR itself or some other native component is crashing and it has nothing to do about it..
Posted by abhinaba | 3 Comments
Filed under: ,

C# generates virtual calls to non-virtual methods as well

Hyderabad Microsoft Campus

Sometime back I had posted about a case where non-virtual calls are used for virtual methods and promised posting about the reverse scenario. This issue of C# generating callvirt IL instruction even for non-virtual method calls keeps coming back on C# discussion DLs every couple of months. So here it goes :)

Consider the following code

class B
{
    public virtual void Virt(){
        Console.WriteLine("Base::Virt");
    }

    public void Stat(){
        Console.WriteLine("Base::Stat");
    }
}

class D : B
{
    public override void Virt(){
        Console.WriteLine("Derived::Virt");
    }
}

class Program
{
    static void Main(string[] args)
    {
        D d = new D();
        d.Stat(); // should emit the call IL instruction
        d.Virt(); // should emit the callvirt IL instruction
    }
}

The basic scenario is that a base class defines a virtual method and a non-virtual method. A call is made to base using a derived class pointer. The expectation is that the call to the virtual method (B.Virt) will be through the intermediate language (IL) callvirt instruction and that to the non-virtual method (B.Stat) through call IL instruction.

However, this is not true and callvirt is used for both. If we open the disassembly for the Main method using reflector or ILDASM this is what we see

    L_0000: nop 
    L_0001: newobj instance void ConsoleApplication1.D::.ctor()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: callvirt instance void ConsoleApplication1.B::Stat()
    L_000d: nop 
    L_000e: ldloc.0 
    L_000f: callvirt instance void ConsoleApplication1.B::Virt()
    L_0014: nop 
    L_0015: ret 

Question is why? There are two reasons that have been brought forward by the CLR team

  1. API change.
    The reason is that .NET team wanted a change in an method (API) from non-virtual to virtual to be non-breaking. So in effect since the call is anyway generated as callvirt a caller need not be recompiled in case the callee changes to be a virtual method.
  2. Null checking
    If a call is generated and the method body doesn't access any instance variable then it is possible to even call on null objects successfully. This is currently possible in C++, see a post I made on this here.
  3. With callvirt there's a forced access to this pointer and hence the object on which the method is being called is automatically checked for null.

callvirt does come with additional performance cost but measurement showed that there's no significant performance difference between call with null check vs callvirt. Moreover, since the Jitter has full metadata of the callee, while jitting the callvirt it can generate processor instructions to do static call if it figures out that the callee is indeed non-virtual.

However, the compiler does try to optimize situations where it knows for sure that the target object cannot be null. E.g. for the expression i.ToString(); where i is an int call is used to call the ToString method because Int32 is value type (cannot be null) and sealed.

Posted by abhinaba | 2 Comments
More Posts Next page »
 
Page view tracker