Welcome to MSDN Blogs Sign in | Join | Help

Computing Time in .NET

One of the pitfalls with the abundance of classes that .NET provides is not picking the right class for the job.  The right selection is especially important when performance is a consideration. In this article, I will use a tool called MeasureIt and walk you through rapidly benchmarking various classes and look at a couple of means of measuring time. 

In this post, I will compare the performance of System.DateTime.Now versus System.DateTime.UtcNow – which one is more efficient and by how much? System.DateTime.Now is frequently used in .NET programming as many applications have a need to get time.    System.DateTime.Now calculates the local time and returns a DateTime object.  But, in many instances, is local time with the overhead for Daylight Savings Time (DST) and Time Zones really needed?  (A separate issue is if you use System.DateTime.Now for measuring time differences and DST kicks in, you may find your end times to be “earlier” than the start times!).

System.DateTime.UtcNow provides the Coordinated Universal Time as opposed to the local time – would this be a better bet than System.DateTime.Now if you don’t need local time? For the impatient, our experiments reveal that the performance of DateTime.UtcNow is 30X better than DateTime.Now.

Anytime you want to find out the relative performance of one class versus another, MeasureIt can be a very handy tool.  It is well worth your time to find the right class for the job, and using MeasureIt the task of benchmarking is made easy.

MeasureIt

Vance Morrison has written a couple of MSDN articles about MeasureIt (he wrote the tool as well).  He calls for measuring performance often, measuring performance early and thinking about performance at design time – amen to that!

The MSDN articles (it is a two part series) can be found at:
http://msdn.microsoft.com/en-us/magazine/cc500596.aspx
http://msdn.microsoft.com/en-us/magazine/cc507639.aspx

You can download MeasureIt  at: http://blogs.msdn.com/vancem/attachment/9403324.ashx

Let me quickly summarize the steps needed to get you running:

  1. Click on the 'MeasureIt.zip' link above.  This brings up a download dialog box.
  2. Click  OK and Open the zip file.
  3. Copy the 'MeasureIt' directory to your hard drive. 
  4. Click on the 'MeasureIt.exe' file
  5. Click on the 'Run' dialog box that comes up.

The detailed user’s guide that comes along with the tool is very useful and I recommend reading it in full.

Type MeasureIt /UsersGuide in a command window to see the user’s guide.
Type
MeasureIt /edit to edit the source and add more benchmarks.

Benchmarking Time

We want to measure how DateTime.Now and DateTime.UtcNow compare. Per the nice user’s guide from Vance on MeasureIt, I  type MeasureIt.exe /edit in a command prompt, which brings up the MeasureIt solution in Visual Studio (isn’t that really cool?) and add a new “area” called MeasureTime  and add the benchmarks for DateTime.Now and DateTime.UtcNow. The code I added to the MeasureIt class in the MeasureIt.cs file is just the following few lines:

  static public void MeasureTime()

    {

        DateTime time;

        timer1000.Measure("DateTime.Now", 1, delegate

        {

            time = DateTime.Now;

        });

 

        long stime;  

        timer1000.Measure("DateTime.UtcNow", 1, delegate

        {

            time = DateTime.UtcNow;

        });

 

       

     

    }

After adding this code, I ran MeasureIt.exe time in a command prompt to filter out all other benchmarks and I get a nice page that opens in Internet Explorer giving me the results and explaining me how to read it.  The results that MeasureIt reports is  normalized to EmptyStaticFunction(). In order to convert the results into absolute time, look for the line  which informs you what 1.0 unit represents {For, these experiments, MeasureIt indicated the results were Scaled where EmptyStaticFunction = 1.0 (1.5 nsec = 1.0 units) }. Thus, 200 units represents 300ns.  The reason that MeasureIt normalizes is to enable comparisons at different times.  When the CPU load is low, you may get very low absolute times; when the CPU load is high, you may get larger absolute times. However, the normalization to EmptyStaticFunction ensures that your comparisons are still valid. For our experiment, since we are only looking at one run, the normalization is not that interesting.

Name

Median

Mean

StdDev

Min

Max

Samples

NOTHING [count=1000]

0.000

0.055

0.166

0.000

0.552

10

MethodCalls: EmptyStaticFunction() [count=1000 scale=10.0]

1.000

1.010

0.029

1.000

1.097

10

Loop 1K times [count=1000]

249.310

249.428

0.289

249.310

250.276

10

Time: DateTime.Now [count=1000]

235.000

237.531

8.357

231.586

261.448

10

Time: DateTime.UtcNow [count=1000]

7.517

7.545

0.274

7.379

8.345

10

 

The first three rows are giving you a basis since the benchmarks we are running are very small and will vary run to run dramatically. The first row just gives you a feel for what measurement error you can expect, assuming your benchmark does NOTHING.  The [count=1000] tells you that the numbers reported are averaged across 1000 runs (if you do what I did and repeat the benchmark 10 times, that means the numbers are averaged across 10000 runs).

The second row acts as a baseline, with 1.0 unit being equivalent to 1.5 ns. In this run DateTime.Now reported 240 units (360 ns).  If during another run, you find that DateTime.Now reported 480 units (720 ns), and MethodCalls takes 2 units (3 ns),  you can conclude that it was just the system variability in the two runs that caused the spike and DateTime.Now did not become slower.

The third row (Loop 1K times) is a dummy loop that tries to kick the CPU into action and out of any low power state that it may have been to make measurements as realistic as possible. Finally, MeasureIt also provides the median and mean values along with the standard deviation it observed run to run.      About 95% of all measurements fall within two standard deviations of the mean.

Okay, enough with the explanation.  The highlighted rows in the table compare DateTime.Now with DateTime.UtcNow.
 DateTime.UtcNow  is almost 30x faster than DateTime.Now! 

Computing local time takes a fair amount of work including getting time zones and setting up DST making it substantially expensive relative to DateTime.UtcNow. Thus, if you don’t want local time, use DateTime.UtcNow.

Conclusion

Using MeasureIt to quickly benchmark different classes that you plan to use in your scenario can be valuable to improving your application’s performance. Calculating time, it turns out is more complex than one would think (having to get time zones, DST, etc. correct). Using the right class for getting time can affect the running time of your scenario significantly if you get time frequently. In conclusion, using DateTime.UtcNow in places where you do not need local time can give your scenario a time boost!

Posted by clrperfb | 0 Comments

Improving Startup Time: A primer on setting base-addresses for managed DLLs

Startup time is one of the most perceptible performance issues for any application.  In this post, we’ll talk about an easy way to improve startup time in many cases.  In particular, if you are building an application with managed DLLs, and your application is deployed on pre-Vista OS’es, this post will teach you how to make your application start faster, by setting base addresses. 

What are base-addresses, and why is setting base-addresses important?
Let us assume that you are loading two executable DLLs (or images) sample1.DLL and sample2.DLL which contain many methods and references to methods. The references are generally absolute memory addresses. These absolute memory addresses within the images are only valid when the executable file is loaded at a preferred virtual address in memory. The preferred base-address for images is something that developers can set.

Let us examine what happens if we don’t set the preferred base-address for the images. The framework defaults the preferred base-addresses to 0x00400000 if you don’t set it explicitly. Thus, both images (sample1.DLL and sample2.DLL) will have the same preferred base-address 0x00400000. Since both images cannot be loaded at the same virtual address, one of the images will have to be rebased; that image will be loaded wherever the OS loader deems fit. Rebasing is expensive because the loader has to now update all the absolute addresses within the image to the new absolute addresses based on where the image actually got loaded. Many pages in the image contain such absolute addresses and thus need to be read and then written to with the new address. As if this weren’t bad enough, all the pages that were written to can no longer be shared with other processes that have loaded the same DLL.  This translates to reading in a lot more disk data when the DLL is loaded (whether it is needed or not).

When should you set preferred base-addresses for managed DLLs?
You should be setting image base-addresses if all the following conditions below are true:

1)      You have a substantial client base on Pre-vista OSes (Vista+ OSes do the necessary relocations at page fault time and thus there is no additional cost if you do not set base-addresses).

2)      You create DLLs (exes are always the first in the process).

3)      You NGen your DLLs (IL DLLs do not have absolute addresses that need to be fixed up) OR you have a mixed managed-native DLL.

4)      You are concerned about startup time (if startup time is not a big factor, it may not be beneficial to NGen either; however, NGening can enable cross process sharing and lower total working set).

5)      Your DLLs are large in size (if your DLLs are below 100K in size, there is not much benefit)

 

Why is setting base-addresses on Vista+ OSes unimportant?

While setting base-addresses is extremely important in Windows XP, in Vista and higher versions of the Windows Operating System, ASLR (Address Space Layout Randomization) moves the image locations randomly for increased security (and also does this efficiently by performing the necessary relocations at page fault time rather than at DLL load time; additionally with ASLR, while the final location is random per machine, it is the same for each process on the machine, which means the relocated data can be shared across all processes).  There may be some marginal cases where setting base addresses in Vista+ OSes has a benefit, but these can be largely ignored.

Why is setting base-addresses on IL DLLs unimportant?
While native code tends to have many absolute addresses, IL code has effectively none.   Thus, even if an IL DLL does not get a preferred base address, it does not cause any relocation overhead.  If you are not using NGen, your DLLs are IL only – but if you care about startup time, particularly warm startup, NGen is highly recommended (A good introduction to NGen can be found at: http://msdn.microsoft.com/en-us/magazine/cc163610.aspx)

How does one set base-addresses?
In Visual Studio, you can set the base-address option from the advanced tab in the project properties by selecting the advanced button.

What should one pick as base-addresses?
The requirement is that no two DLLs overlap.   Any scheme that accomplishes this is sufficient.   One simple way of achieving this is picking a spot that system DLLs do not use (0x40000000 is a good spot; this is different from the default base address 0x00400000 I mentioned earlier) and assigning each DLL a range so that they are packed together (typically it is good to allow 20% for DLL growth).   Finally, check that you succeeded using the procedure explained in the next question.

For a mixed-mode assembly (an assembly containing both native and managed code), both the IL and the NGen image may have to be loaded into memory. For such assemblies, NGen selects the base address of the NGen image to be equal to the base address of the MSIL assembly plus the size of the MSIL assembly plus some padding to round up to the nearest page boundary. NGen images can be as large as 3X times the size of an IL image, so ensure that the base-addresses are chosen appropriately.

Why (and how) should I check for relocations if I set base-addresses?
Even if you diligently set base-addresses, if there are base-address conflicts, performance will be impacted as expected. This can happen for a number of reasons, including DLLs or COM components you didn’t think about that get loaded into your process.  Checking for relocations can help identify collisions and then eliminate them. If your application is hurting for virtual address space, base-address collisions cannot be avoided. You will have to make a determination on which DLLs will collide in that case - choose the smallest DLLs to lower performance impact.

You can check relocations using the Sysinternals tool – Process Explorer. After starting Process Explorer, click on Options –> Configure Highlighting, and check the ‘Relocated DLLs’ at the bottom (it is off by default).  Select the DLL view in the lower pane (View à Lower Pane à DLL View) and when you select a process name, the DLLs loaded in that process in the lower pane and those DLLs that are being rebased will show up highlighted.

You can download Process Explorer from: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Alternatively,  you can use the command line tool ListDLLs to check for base-address collisions; ListDLLs can be obtained from: http://technet.microsoft.com/en-us/sysinternals/bb896656.aspx

 If you want to check the preferred base address of a binary without launching the process, you can use the "dumpbin /headers"  command shipped with the SDK. The "image base" data is the preferred base address.

Conclusion
Overall, you can see that this is generally a simple process – identify if setting base-addresses matter to you and if they do set the addresses, check for collisions and fix them if found.  Despite the simplicity, setting base addresses can have a significant impact on your application if the conditions mentioned in this article apply.

Posted by clrperfb | 0 Comments
Filed under: ,

.NET Framework Performance Survey

Update: Thank you to everyone who participated - we had a good response. This survey will be closed on 06/25/2009 at 5.00 PM PST.

 Want us to fix a particularly nagging perf problem? Dying to tell us your awesome idea about an optimization? Here is an opportunity for you to provide us feedback on your level of satisfaction with .NET Framework performance and voice your opinions and thoughts on what we should be focusing on in the future. This single page survey will take about 10-15 minutes to complete the questionnaire.

Please help us serve you better by filling out the survey at:
http://dotnetfxperf2009.questionpro.com/

Posted by clrperfb | 2 Comments
Filed under: , ,

Improving NetFX 3.5SP1 Application Startup

As most of you probably experienced, NetFX 3.5SP1 offers significant performance improvements over NetFX 3.5.However, we received some reports where NetFX 3.5SP1 installs are seen to be making some select few applications startup slower than they were in NetFX 3.5, whereas for most applications startup performance improves significantly with NetFX 3.5SP1.

The possible reason for this anomaly is because the installed images are being dispersed into many fragmented pages in a fragmented volume, thereby increasing disk i/o during start up. This issue can be fixed very easily by doing a full defragmentation of your hard drive.

Note that in Windows Vista, it automatically defrags your disk at scheduled intervals, thereby resolving the issue over the course of time.  Similarly, on WindowXP the operating system will defragment files that are used at startup of an application within 3 days of their use to optimize their cold startup.  

However, if one wishes to maximize performance immediately following a NetFX 3.5SP1 install, a defrag is suggested.

To defrag your harddrive in Vista, select Start --> All Programs --> Accessories --> System Tools --> Disk Defragmenter --> Defragment now.

In Windows XP, select Start->Programs->Accessories->System Tools->Disk Defragmenter --> Defragment.

Posted by clrperfb | 3 Comments
Filed under: , ,

Using the System.GC APIs to Improve Performance

Chris Lyon here.  You may remember me from such blogs as How I Learned to Stop Worrying and Love the GC.  I’m writing this blog entry to point out some of the System.GC APIs that can be used to help improve the performance of your managed application.

 

AddMemoryPressure and RemoveMemoryPressure

The Garbage Collector (GC) handles managed memory and only managed memory.  That means it’s up to you to manage any other resources your application holds onto (files, network or database connections, etc).  AddMemoryPressure and RemoveMemoryPressure, added in .NET 2.0, are used to give a hint to the GC about the size of these unmanaged resources. 

Consider the following contrived class which holds a handle to an open file (AllocHandle and FreeHandle are made-up functions for illustration purposes):

class FileHandleHolder

{

    protected IntPtr _fileHandle;

 

    public FileHandleHolder(string fileName)

    {

       _fileHandle = AllocHandle(fileName);

    }

 

    ~FileHandleHolder()

    {

FreeHandle(_fileHandle);
    }

 

}

 

The handle itself is an IntPtr, which takes up much less memory than the file itself.  As far as the GC is concerned, an instance of FileHandleHolder doesn’t exert much memory pressure, so the GC tunes itself accordingly.  If however, fileHandle pointed to a 1 GB file, the GC still thinks there isn’t much memory pressure caused by this class, since the file is not on the managed heap.  So how do we trick the GC into taking into account our 1 GB file?  Let’s make two small changes to our FileHandleHolder class:

class FileHandleHolder

{

    protected IntPtr _fileHandle;

 

    public FileHandleHolder(string filename, long fileSize)

    {

       _fileHandle = AllocHandle(fileName);

GC.AddMemoryPressure(fileSize);

    }

 

    ~FileHandleHolder()

    {

FreeHandle(_fileHandle);

GC.RemoveMemoryPressure(fileSize);


    }

 

}

 

Our first change is to the constructor.  We can pass the size of the actual file to GC.AddMemoryPressure.  This will tell the GC that this application has an additional 1 GB of memory pressure to it, and the GC will adjust its tuning accordingly.  The second change is to the finalizer.  We call GC.RemoveMemoryPressure to tell the GC there is 1 GB less pressure.

A word of warning, make sure you balance your Add/Removes, lest you cause the GC to start collecting more aggressively and hurting your performance.

Collect

We’ve all heard the advice: don’t call GC.Collect.  It interferes with the GC’s own tuning and unless you really know what you’re doing, you can hurt your application’s overall performance.  In .NET 3.5, we added an overload to GC.Collect that takes a GCCollectionMode enum value.  In places where you think you could benefit from a call to GC.Collect (Perf Guru Rico Mariani has some advice about that here: http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx), you can call GC.Collect(2, GCCollectionMode.Optimized), which tells the GC to use its best judgment about whether to actually do a GC.   Based on the GC’s tuning to that point, it will decide if the GC heap will benefit from a collection or not.

 

SuppressFinalize

Finalizers are bad for performance.  After being marked no longer reachable from user code following a collection, your finalizable object stays in memory until its finalizer is run, and only after the next collection is the memory actually reclaimed.  And not just your finalizable object, the entire object graph your object references.

To avoid the need for finalizers, we recommend implementing the Dispose Pattern (http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx).  This is where GC.SuppressFinalize comes in.  Let’s consider our FileHandleHolder class again, but this time have it use the Dispose Pattern:

class FileHandleHolder : IDisposable

{

    protected IntPtr _fileHandle;

 

    public FileHandleHolder(string filename, long fileSize)

    {

       _fileHandle = AllocHandle(fileName);

GC.AddMemoryPressure(fileSize);

    }

 

    ~FileHandleHolder()

    {

Dispose(false);
    }

 

    public void Dispose()

    {

       Dispose(true);

       GC.SuppressFinalize(this);

    }

 

    protected virtual void Dispose(bool disposing)

    {

FreeHandle(_fileHandle);

GC.RemoveMemoryPressure(fileSize);

    }

 

}

Using the Dispose Pattern, the GC gets the hint that the memory pressure is removed sooner than waiting for it to be collected then finalized, and the GC can resume its tuning.  Stay tuned for my next blog post that will describe some of the new GC APIs added in .NET 3.5 SP1.

This post was authored by Chris Lyon of the CLR performance team at Microsoft Corporation.

Posted by clrperfb | 4 Comments
Filed under: , , ,

Track down DLL loading using Visual Studio

Application performance matters --- including start up times, working sets and memory consumption.

One path leading to more efficient code is loading fewer DLLs. One should only be loading modules that are really needed. However, it is very easy to accidentally load more DLLs at startup than necessary leading to lower performance including longer startup times and higher memory consumption.

While there exists a variety of tools which tell you which processes are loaded (examples include tlist,  process explore and visual studio -> modules window),  one often needs to find out why  a module was loaded to try to eliminate the DLL load to improve performance.

The callstack at the time the DLL was loaded helps in identifying  why a particular dll was loaded, and therefore is essential for performance diagnostics.

This blog shows you how to do all this using Visual Studio!  All the files you need to follow this example are provided in a ZIP file at the end of this post. 

Consider the following (somewhat contrived) program.  This program was intended to represent a program that could write is output either as XML or as simple text.  Let us assume that the XML option as the rare case.   Let us also assume that we care about the working set of this program.  When we run it to completion under the Visual Studio debugger, we notice in the Debug -> Modules window that System.Xml.Linq.ni.dll  is loaded even in the case when even in the common case where the user specified text output.  This is clearly inefficient, and this investigation shows how we can track down the cause of this ‘questionable’ DLL load.    

Program.cs

 

using System;

using System.IO;

using System.Xml.Linq;

 

class Program

{

    static void ProcessArgs(string[] args)

    {

      if (args.Length == 2 && args[0] == "text")

        {

            File.WriteAllText(args[1], "Here is the data I am writing");

        }

        else if (args.Length == 2 && args[0] == "xml")

        {

            XElement myXml = new XElement("data", "Here is the data I am writing");

            myXml.Save(args[1]);

        }

    }

 

    static int Main(string[] args)

    {

        ProcessArgs(args);

        return 0;

}

}

 

 

The overall structure of the investigation is to set a breakpoint at the OS method that loads the DLLs.  When we are at the breakpoint we can determine  which DLL is being loaded.  When we find the DLL we are focusing on, we have a call stack, and this callstact is typically the key to understanding how our program cause the load (an thus how we might eliminate the load).

Step 1: Ensure access to the operating system symbols through the following commands in your VS command window

mkdir c:\symbols

set _NT_SYMBOL_PATH=SRV*C:\symbols*http://msdl.microsoft.com/download/symbols

Step 2: Launch the application, debugging it as an unmanaged application.  This is needed because VS by default hides all activity in the runtime itself if you debug it as a managed application.  By doing this, you get visibility into all DLL loads.

start devenv /debugexe <command line of application>

In our example, this translates to

start devenv /debugexe DemoDllLoad.exe  text output.txt

(assuming Program.cs was compiled into the executable DemoDllLoad.exe)

Step 3:  Right click on the EXE name in the solution explorer -> select Properties -> Set debugger type to ‘Native Only’

Step 4: Add a new breakpoint for the system call LoadLibraryExW@12.  This OS function is called every time a DLL is loaded.  To do this bring up the breakpoint dialog (Debug à New Breakpoint à Break at Function) and enter the following into the function field (ignore the other fields)

       {,,kernel32}_LoadLibraryExW@12                      

Select Apply and then click OK.

 

Step 5: Hit F5 (Go).  This will now break every time a DLL is loaded, each time you will see a call stack in the call stack window where the DLL was loaded. 

Step 6: The public symbols for the OS do not decode the arguments, but you can work around this by decoding the arguments ‘by hand’.  After hitting the breakpoint for _LoadLibraryExW@12, go to the watch window (Ctrl-D W), and add the following expression to it

*(wchar_t**) (esp+4)

You should now see the string value of the DLL being loaded.

Step 7: Keep hitting F5 until the DLL you are interested in is in the watch window.  In our example we keep going until System.Xml.Linq.ni.dll  is loaded.

Step 8: Unfortunately, only the UNMANAGED part of the stack is displayed in the” Callstack window”.  This may not be interesting (you care about the managed part of the stack).  To see the managed part of the stack select the “Immediate window” and type the following (when System.Xml.Linq.ni.dll  appears in the watch window):

.load sos                                                                             

(This only needs to be typed only once.)

!ClrStack                              

(You can use !Help for help)

Step 9: Observe the immediate window.  In our example you will see something similar to the following:

 

PDB symbol for mscorwks.dll not loaded

OS Thread Id: 0x14ec (5356)

ESP       EIP    

0015ed4c 762430c3 [PrestubMethodFrame: 0015ed4c] Program.ProcessArgs(System.String[])

0015ed5c 007f008d Program.Main(System.String[])

0015ef7c 79e7c74b [GCFrame: 0015ef7c]

This tells us that the DLL (System.Xml.Linq.ni.dll) got loaded when Program.ProcessArgs() was called from Main() (and was being Jitted --- PresubMethodFrames are created for JIT compiling a method ).

Step 10: The reason why this DLL was getting loaded irrespective of the input is because the JIT compiler does not know what code paths will be taken, and has to load all DLLs referenced by that method when compiling it.  This is because Program.ProcessArgs() had calls to methods in System.Xml.Linq.ni.dll that DLL had to be loaded (even if the methods are not ultimately called). 

To prevent these unwanted DLL loads from happening, let us put the Xml processing in a separate routine as follows:

using System;

using System.IO;

using System.Xml.Linq;

 

class Program

{

    static void XmlProcessingRoutine(string filename)

    {

        XElement myXml = new XElement("data", "Here is the data I am writing");

        myXml.Save(filename);

    }

 

    static void ProcessArgs(string[] args)

    {

      if (args.Length == 2 && args[0] == "text")

        {

            File.WriteAllText(args[1], "Here is the data I am writing");

        }

        else if (args.Length == 2 && args[0] == "xml")

        {

           XmlProcessingRoutine(args[1]);

        }

    }

   

 

    static int Main(string[] args)

    {

        ProcessArgs(args);

        return 0;

    }

}

 

Now, System.Xml.Linq.ni.dll and System.Xml.ni.dll will only get loaded if the function XmlProcessingRoutine() is invoked, which will only happen when Xml output is selected in the command. Thus, for other cases, when text output is desired we have avoided loading two additional unwanted dlls!  While in this case the program was probably simple enough that we could have guessed this without knowing the call stack that loaded the DLL, in real programs the call stack is usually the key to determining why a DLL is loaded.

 

The source files can be found as a zip file as an attachment here.

This post was authored by Vance Morrison (Principal Architect) and Subramanian Ramaswamy (Program Manager) from the CLR Perf team at Microsoft.

Posted by clrperfb | 1 Comments
Attachment(s): DemoDllLoad.zip

Adding Custom Actions to NGen an Assembly upon Install

This  document details how to use custom actions to Ngen (generate a native image) upon installation of a project.  Assemblies that are NGen’ed have better startup performance than those that are JIT’ted: http://msdn.microsoft.com/en-us/magazine/cc163610.aspx

Step 1: Creating and building your sources

I am assuming that you have created a new project, written all your source files, built the project and are ready to go.  I am assuming that your project name is MySources and you also created a solution with the same name, MySources.

 

If all is well, you should see something similar to the following, with probably a lot more files under your MySources project:

               

           

 

 

Step 2: Creating and building the NgenHelperClass

 

(a)    While the MySources solution is selected, under the File menu, click Add ->New Project . If you are not seeing these options under the File menu, it is because your program is still executing and you have not exited debugging.

(b)   Select under Project Types , Visual Basic -> Class Library; Name it NgenHelperClass; Click OK.

(c)     Click the NgenHelperClass project on the Solution Explorer on the right and select Project menu-> Add New Item -> Common Items -> General  -> Installer Class; the default name Installer1.vb is fine. Note: If Solution Explorer cannot be seen, open up the View menu and select Solution Explorer; the NgenHelperClass project has to be selected for this to work as described.

(d)   Click Add, and in the succeeding screen, click to show the code view

(e)    Add the following code to the top of the module, below

  Imports System.Configuration.Install:

Imports System.Runtime.InteropServices

Imports System.Text

(f)      Add  the following declaration below Public Class Installer1:

 

Private Declare Function GetCORSystemDirectory Lib "mscoree.dll" _

(<Runtime.InteropServices.MarshalAs( _

System.Runtime.InteropServices.UnmanagedType.LPWStr)> _

ByVal Buffer As System.Text.StringBuilder, _

ByVal BufferLength As Integer, ByRef Length As Integer) As Integer

 

(g)     In Installer1.vb, after the End Sub statement for MyBase.New, add the following procedure to override the Install procedure of the base class:

  <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Demand)> _

Public Overrides Sub Install(ByVal savedState As  _

  System.Collections.IDictionary)

 

        MyBase.Install(savedState)

        Dim Args As String = Me.Context.Parameters.Item("Args")

 

        If Args = "" Then

            Throw New InstallException("No arguments specified")

        End If

 

        ' Gets the path to the Framework directory.

        Dim Path As New System.Text.StringBuilder(1024)

        Dim Size As Integer

        GetCORSystemDirectory(Path, Path.Capacity, Size)

 

        Dim P As Process

        ' Quotes the arguments, in case they have a space in them.

        Dim Si As New ProcessStartInfo(Path.ToString() & "ngen.exe", " install " & Chr(34) _

           & Args & Chr(34))

        Si.WindowStyle = ProcessWindowStyle.Hidden

        Try

            P = Process.Start(Si)

            P.WaitForExit()

        Catch e As Exception

            Throw New InstallException(e.Message)

        End Try

    End Sub

 

 

    <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Demand)> _

   Public Overrides Sub Rollback(ByVal savedState As  _

     System.Collections.IDictionary)

 

        MyBase.Install(savedState)

        Dim Args As String = Me.Context.Parameters.Item("Args")

 

        If Args = "" Then

            Throw New InstallException("No arguments specified")

        End If

 

        ' Gets the path to the Framework directory.

        Dim Path As New System.Text.StringBuilder(1024)

        Dim Size As Integer

        GetCORSystemDirectory(Path, Path.Capacity, Size)

 

        Dim P As Process

        ' Quotes the arguments, in case they have a space in them.

        Dim Si As New ProcessStartInfo(Path.ToString() & "ngen.exe", " uninstall " & Chr(34) _

           & Args & Chr(34))

        Si.WindowStyle = ProcessWindowStyle.Hidden

        Try

            P = Process.Start(Si)

            P.WaitForExit()

        Catch e As Exception

            Throw New InstallException(e.Message)

        End Try

    End Sub

 

 

    <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Demand)> _

     Public Overrides Sub Uninstall(ByVal savedState As  _

     System.Collections.IDictionary)

 

        MyBase.Uninstall(savedState)

        Dim Args As String = Me.Context.Parameters.Item("Args")

 

        If Args = "" Then

                   Throw New InstallException("No arguments specified")

        End If

 

        '  Gets the path to the Framework directory.

        Dim Path As New System.Text.StringBuilder(1024)

        Dim Size As Integer

        GetCORSystemDirectory(Path, Path.Capacity, Size)

 

         Dim P As Process

        ' Quotes the arguments, in case they have a space in them.

  Dim Si As New ProcessStartInfo(Path.ToString() & "ngen.exe", "       uninstall " & Chr(34) _ & Args & Chr(34))

  Si.WindowStyle = ProcessWindowStyle.Hidden

        Try

            P = Process.Start(Si)

            P.WaitForExit()

        Catch e As Exception

            Throw New InstallException(e.Message)

        End Try

End Sub

 

(h) Build solution; you should see that it builds two projects now, and succeeds. If not, you have done something wrong.

(i) The NgenHelperClass is now built; this class can be re-used with other projects as appropriate.

 

 

 

Step 3: Building the actual installer

 

(a)    With the solution MySources selected, under the File menu, Add New Project.

(b)    Select Other Project Types -> Setup and Deployment in the project types frame.

(c)     In the Templates frame, select Setup Project

(d)   In the Name field type MyInstaller; Click OK.

(e)   If all went well, you should see the following screen:

 

 

 

 

(f)     Click on Application Folder on the File System on Target Machine window, right click on Application folder, Select Add-> Project Output

(g)    Click on Primary Output while MySources is selected in the Project field; click OK.

(h)   Again repeat Step (f), and  add NgenHelperClass to Primary Output by selecting NgenHelperClass on the Project field; click OK.

(i)      Now you should have two primary outputs selected in the application folder as below:

 

 

(j)     Now select the MyInstaller project in solution explorer, and on the View menu , select View -> Editor -> Custom Actions. The following window should now be visible:

 

        

 

 

(k)    In the custom Actions (MyInstaller) window, right click on Custom Actions and select Add custom action;

(l)      In the Select Item in Project, double click Application folder, and select Primary output from NgenHelperClass (Do *NOT* select the primary output from MySources)

(m) Click OK; you should see that the primary output from NgenHelperClass is now visible for all  the  four actions (Install/commit/rollback/uninstall). It is not generally necessary to add this for commit unless your deployment requires it. Select the “Primary Output Custom Action” on Commit and right click and select delete.

(n)   Click on the primary output from NgenHelperClass for the Install folder; ON the properties window you should see CustomActionData field; in this field type the following corresponding to the executable for your sources: /Args="[TARGETDIR]MySources.exe"

(o)   Repeat  the above step for Rollback/Install

(p)   Click Save; On the Build menu (with MyInstaller selected on solution explorer), choose Build MyInstaller. Note – the installer is not built when you choose build solution at any point – beware.

(q)   In the Properties window set the field “ProductName” to the name you would like to see in the Add/Remove programs menu in control panel. We selected HelloWorldApp as the Product Name.

(r)     Select Release option instead of the default debug option. On the Build menu, select Build Solution, followed by Build MyInstaller.

 

 

Step 4: Verifying whether it really worked

 

(a)    To install on your development computer: Select the MyInstaller project in Solution Explorer. On the Project menu, choose Install.

(b)   To deploy to another computer: In Windows Explorer, navigate to your project directory and find the built installer. The default path in Windows Vista will be C:\Users\yourloginname\My Documents\Visual Studio 2008\Projects\mysources\MyInstaller\Release\MyInstaller.msi. Copy MyInstaller.msi, Setup.exe, and all other files and subdirectories in the directory to another computer and install.

(c)    Navigate to the assembly folder %windir%\assembly (for example, C:\Windows\assembly) and find MySources under the appropriate Native Images folder. If there are multiple native images folders, you have multiple runtimes installed. Select the folder based on the runtime you used to build your sources. If you found MySources, that means that your Ngen was successful!

(d)    To uninstall the application: In Windows Control Panel, double-click Add or Remove Programs. In the Add or Remove Programs dialog box, select HelloWorldApp and click Remove, and then click OK to close the dialog box.

 

This post was authored by Subramanian Ramaswamy with assistance from Momin Al-Ghosien and Ashok Kamath, members of the CLR Performance Team at Microsoft.

Posted by clrperfb | 0 Comments
Filed under: , , ,

Investigating Framework Performance on Itanium: Rudimentary Considerations

So let's begin the Performance conversation! The area I'd like to delve into for this post is the performance of managed code on Itaniums.

One of the first tasks I took on when I joined the Framework Performance team( as a  Program Manager) was to continue to improve the performance of managed code on Intel Itanium architecture and cleanup our problem areas. This post summarizes some of the performance issues that we are investigating as we move on to the next major release of the .NET framework.

This has been made possible by a joint effort between Microsoft and other partners, one of them being the Itanium Solutions Alliance (ISA). Microsoft is a charter member of the ISA and we are excited to work with the other members of ISA, and to further enhance the performance of the .NET Framework on Intel Itanium Architecture.

Here is an outline of areas we're investigating for improved performance on Itanium architecture.

Evaluation and Optimization considerations
A large portion of our work list is investigating and evaluating both the existing JIT compiler and proposed changes. For example, global scheduling could potentially improve execution speed by reducing load stalls and making more instructions available for bundle scheduling. We plan to investigate what impact enabling a global scheduler would have on code performance and code correctness, especially garbage collection.

There are a number of small changes we are looking at that may have a big impact on code quality (size and/or execution speed). As in, the code to access values in a 8KB or larger stack frame was inefficient. Reversing the order of the stack (frame) pointer and offset allows us to improve this code.

Local Optimization
One of the other problems we have identified is that we currently do not optimize for larger functions. This was done in an effort to improve compilation time. Unfortunately the side effect is to make these large functions even larger and slower. We are investigating several alternatives to improve the generated code quality without having as large an impact on compilation time.

Loop Optimization
Although optimizing loops is not important for every application, it is important for some of them. We are looking into solutions to enable loop unrolling or software pipelining , and if this can be done without too large an impact on compile time or code size.

We're always looking for feedback from our valued customers, so if you've experimented and/or have specifics of performance issues you've noticed on Itaniums, please do share your results.
 This post was authored by Snesha Arumugam, a Program Manager for Framework Performance at Microsoft.

 

Posted by clrperfb | 1 Comments
Filed under: ,

Welcome to the CLR and Framework Perf Blog!

 

This blog will contain interesting tips and tidbits on all things CLR and the .NET Framework Perf related. It will include posts on how to improve performance from an developer perspective, provide how tos and tutorials on a bunch of perf related stuff, provide tips of debugging perf related problems and solicit feedback from our customers. Briefly --- anything perf related.

Don’t know what CLR is? It is an acronym for Common Language Runtime. 
Think of the CLR as the backbone of the .NET framework (just like everything under the hood is the backbone for your car). It is the stuff that takes the compiled program and translates it into assembly and executes it (pressing your accelerator, for example, results in higher revs, how?). It also provides all sorts of support and services for your program like memory management and exception handling to name just two (How does the car display your speed? Your mileage? Keep it in cruise?). Essentially the CLR does all the major chunks and all the bits and pieces to keep your program running smoothly (I do not have to put an analogy here, do I?).

Whenever you write your code in any managed language, e.g., C#, VB, VC++, you name it, you are using the CLR. (Try using your hands on the accelerator, it will work as long as the accelerator is pressed). The CLR cares about the common intermediate language (CIL) that is generated by compiling code in the above languages and gets them to execute on many systems.

Now, for the customary introductions. My name is Subramanian Ramaswamy (Mani) and I am a Program Manager with the CLR perf team. I will try to ensure that the blog updates atleast once monthly; if this blog is not updated, I am the guy you can holler at. Many of the blog posts you are likely to see will be from individual members from the CLR perf team.
This blog is targeted to software engineers who care about the performance of their managed code as it relates to the runtime which is executing it. Better knowledge of the runtime results in exploiting it better for faster code.
 
The CLR Perf team is focused on improving the performance of the runtime and a lot of talented people are working towards that. Feel free to put in the comments field topics on which you would like to see us post. You can tell us where we can improve things as we strive to improve your experience.

 

Posted by clrperfb | 0 Comments
Filed under: ,
 
Page view tracker