Creating NGEN PDBs for Profiling Reports

Creating NGEN PDBs for Profiling Reports

  • Comments 24

Update: Visual Studio 2013 will generate PDBs automatically when using the CPU Sampling or the CPU Usage tool in the Performance and Diagnostics hub. See this post for more details!

When profiling managed applications on Windows 8 any samples in an NGEN’d module will appear in the report as [NI module name] instead of showing the function name, which obviously makes it difficult to understand the report.

For example in the screenshot below you see [], and I can see in the output window that I failed to load symbols (PDB files) for even though I enabled Microsoft Symbol Servers in my Visual Studio symbol settings (I can tell that the symbol server is working, because immediately below the “failed to load” for I can see that I did load symbols for twinapi.dll)


Unfortunately without symbols, you cannot see function names in native modules so all I can tell in the above screenshot is that I’m calling something in but I have no idea which function I am calling; where if I’m able to get the symbol file for I’ll be able to understand what I’m calling in mscorlib that is expensive. So in this blog post I will show you how to resolve this issue in four steps, but first let’s understand why this is happening.


On Windows 8 the profiler uses a different underlying technology than what it does on previous versions of Windows, which is why the behavior is different on Windows 8. With the new technology, the profiler needs the symbol file (PDB) to know what function is currently executing inside NGEN’d images.

NGEN modules are native modules that are generated on the local machine from the original IL module, so there is no PDB file on the Microsoft symbol servers for framework modules. Furthermore, during NGEN on the local machine there is no PDB file automatically generated for you. Fortunately it’s possible to generate the PDB file yourself and point the profiler to it, so let’s look at the four steps necessary to do that.

Step 1: Determine where the NI module is on disk

  1. Go to the “Modules” view in the profiler report.     
  2. Right click on any column header
  3. Choose “Add/Remove Columns…” from the context menu    
  4. In the dialog box that pops up, choose “Module Path”    
  5. Click OK

The module path column now tells you where on disk the module was during collection.

Here is a screenshot from my local example:


Step 2: Create the PDB

To create the PDB, you’re going to use the Native Image Generator (ngen.exe) that ships with the .NET framework. Since NGEN’d images are native, it’s important you use the copy of ngen.exe that matches the architecture of the application you are profiling (x86/x64/ARM). For example if the application is running 64 bit on Windows 8 RTM then you would need to reference the copy of ngen.exe in “C:\Windows\Microsoft.NET\Framework64\v4.0.30319”

  1. Open a command prompt on the machine where you ran the application during profiling (if you remote profiled a Windows Store App, you have to do this on the machine you were running the app on while you were profiling. It will not work if you do it on the machine you are viewing the report on)
  2. Decide if you just need to see the names of the functions (use this for .NET libraries*), or if need to be able to get back to the original source file including the ability to see which lines of source code were executing most frequently in the Function Details view (only recommended for modules that are part of your project):
    If you don’t need to get back to source then the process is very simple: In a command prompt type “[Microsoft.NET Path]\ngen.exe createPDB [NI module including the full path from step 1] [directory to store PDB]”, and the PDB for the NGEN’d module will be placed in the directory you specified to store the PDB
    This is an example of generating an NGEN PDB for 32bit

If you do need to get back to source
then you will need the PDB for the original pre-NGEN’d module. Once you’ve located that type “ngen.exe createPDB [NI module including the full path from step 1] [directory to store PDB] /lines [directory containing the original PDB]”
NOTE: ngen.exe executes within the security context of the module you are generating the NGEN PDB for. So if you are generating an NGEN PDB for a module that is part of a Windows Store App (this does not mean a framework module such as mscorlib.dll referenced by a Store App), then the output path for the NGEN PDB will need to be in a folder the app has access to (placing it next to the NI module is easiest). Similarly, if you are using the /lines flag, you will need to ensure that that the original PDB is also in a location accessible to the Windows Store app (again next to the NI is easiest). Once the PDB has been generated, you can move this to any location you like.

Below is an example of generating an NGEN PDB with the /lines flag for a module in my Windows Store App.


*PDBs from the Microsoft Symbol Servers do not support the /lines flag, so will not work for generating line level information for .NET modules

Step 3: Add the PDB to your symbol path

In the Symbols page, add the folders containing the NGEN PDBs you created in step 2. This is what that looks like on my machine:


Step 4: Open the profiler report

Close the report showing the [NI modules], and open it again; assuming you did steps 1-3 correctly you will now see method names instead of [NI module]. For example, using the PDBs I created in Step 2 and modifying my symbol path per Step 3, when I reopen the report that generated my original screen shot I see the following:


NOTE: The reason the “Exclusive Samples %” changed from the first screenshot, is the profiler is now able to distinguish between the individual functions inside, where in the first screenshot you only see the total percentage for the entire module

In Closing

Once you’ve created an NGEN PDB for a module, all future reports will reuse the PDBs you have already created. However, if the module is updated or replaced (e.g. it is for your Window Store App and you rebuild it, or there is an update to the .NET framework), then you will need to generate a new NGEN PDB to match the new version of the module.

Hope that helps and I'd love to hear any questions/feedback that you may have so please leave a comment below.

Leave a Comment
  • Please add 5 and 5 and type the answer here:
  • Post
  • It is a thing without how to perform automatically?

  • @Anon

    Unfortunately automatically generating the pdb's for NGEN' images was something that we didn't have time to implement for Visual Studio 2012.  It is however on our backlog to implement in the next version of Visual Studio.

  • @Andrew

    How about a power tool or powershell script to help us out?    (Grab Source-Indexed PDB's from internet + then generate native PDB)

  • @Josh

    This is something that is on my radar. I won't be able to get anything done before the holidays, but I'll let you know when I have something.

  • Thank you for the info! Just run into the same issue when profiling my app and having read this before saved a lot of time. I also created a PowerShell script that creates the PDB files for all currently installed NGEN-ed assemblies:

    I did try to use symbols from as parameter to /lines but it did not work - ngen kept complaining that the PDB files do not match :( The code to do that is still in the script if someone wants to experiment.

  • @Knaģis,

    Thanks for posting this script.  Two things:

    1.  Per your comment about /lines not working correctly, it may not have been super clear when I mentioned this above (my apologies) but the PDBs from the Microsoft Symbol Servers for .NET assemblies don't support the /lines functionality

    2.  It looks like your power shell script is only generating the NGEN PDBs for Framework assemblies that install to the \Windows\assemblies directory.  It might also be interesting to add functionality to generate the PDBs for NGENd user modules as well.  These are placed under \<user>\Local\Packages (note my comment above that the PDBs need to be created in the same directory as the .ni module, then you can move them to the symbol cache, and apologies I still have not had a chance to create this myself yet)

  • So, is it possible to get a properly formatted version of those PDB's to get line numbers? If so, how do we get them (or is this just not accessible at the moment to those of us outside MS?).

  • @Gordon

    The public symbols published on the "Microsoft Symbol Servers" option in your symbol settings dialogue will not support this.  Symbols available from the source server will (enable .NET Source Stepping under Tools -> Options -> Debugging and it will download the symbols available) if there is a .pdb available.  Unfortunately there are very few of these, and they are frequently out of date when updates are published to the framework, and it must be an exact match for it to work.  Otherwise you will receive an error.

  • I tried to createPDB for (Silverlight 5.1.20513.0) but with no luck. I'm getting "The specified native image is not valid." Am I missing something?

  • @scavo

    At this time Silverlight assemblies use a different NGEN process than desktop .NET assemblies which doesn’t support NGEN pdb’s.  Unfortunately the Visual Studio profiler doesn’t currently have a way to get this data and show it to you, however if you are blocked the .NET team has released PerfView ( which supports CPU sampling and can get the data ordinarily contained in an NGEN pdb via rundown from the process each time you profile (it should automatically do the right thing, but if not use the /ForceNGenRundown flag.  Note: the NGEN rundown will likely take a while to complete).

  • Shouldn't this work out of the box? Is it included in VS 2013 now? Thanks.

  • @Karl: NGEN PDBs are now generated automatically in Visual Studio 2013 for Windows Store Apps. For Desktop or ASP.NET apps you will still need to follow these manual instructions.

  • Hello, the commands worked well for and However, for clr.dll unfortunately I failed to get pdb created:


    rk64\v4.0.30319\ngen.exe createpdb C:\Windows\Microsoft.NET\Framework64\v4.0.303

    19\clr.dll C:\nativesymbols

    Microsoft (R) CLR Native Image Generator - Version 4.0.30319.17929

    Copyright (c) Microsoft Corporation.  All rights reserved.

    The specified native image is not valid.

    Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))

    Please help me out. Thanks.

  • @Dodd: clr.dll is a native dll, so you'll need to get symbols from the Microsoft Symbol Servers under Tools -> Options -> Debugging -> Symbols.  (if you have this enabled it is possible there is a recent update to clr.dll, and the matching symbols are not up yet on the Microsoft Symbol Servers, but should be soon

  • This is not working for me with .NET 4.5 and VS2013. I have followed the instructions and still get:

    Failed to load symbols for C:\Windows\assembly\NativeImages_v4.0.30319_32\WindowsBase\2292e2e421f423b42b496da2f12e4f0e\

    This is on 64-bit Windows 8.1 profiling a 32-bit application.

Page 1 of 2 (24 items) 12