DCSIMG
April 2012 - Posts - All Your Base Are Belong To Us

All Your Base Are Belong To Us

Mostly .NET internals and other kinds of gory details

April 2012 - Posts

Second Meeting of the Jerusalem .NET/C++ User Group

The second meeting of the Jerusalem .NET C++ User Group will take place on May 29. This time we’ll be talking about advanced C++ topics. If you’re a developer in the Jerusalem area working with C++, this is the user group for you! Slides from the previous meeting’s talks are available online if you’d like to catch up on what you might have missed last time.

The agenda for this meeting is as follows:

18:00-18:15 – Networking and refreshments
18:15-19:00 – Portable lock-free use of STL containers (Adi Shavit)
19:00-19:15 – Networking and refreshments
19:15-20:00 – Undocumented native debugging tricks (Ofek Shilon)

Undocumented native debugging tricks
Visual Studio provides great debugging facilities as is – but, it also contains a tremendous wealth of useful debugging features, that just never matured enough to be documented and supported. Such hidden features range from enhanced interaction with the debugee, improved debugging productivity, better state diagnostics, better exploration of code flow, and more. The talk would survey as many of those goodies as time permits.

Portable lock-free use of standard STL containers
Parallel and concurrent hardware is becoming more and more pervasive and, in turn, demand for high performance and fast response of these concurrent systems is growing. One modern go-to solution are lock-free data structures. A lot of research has recently produced many lock-free and wait-free data-structures. However, these are often data-structures for very specific use-cases. Portable, well-tested and suitably licensed implementations are still hard to come by. I'll present a scheme for providing portable lock-free access to, and modification of, existing and standard STL containers. The scheme can also be adapted to most other non-STL container. With a compliant C++11 compiler, only the std library is required. On older compilers can use boost to provide the missing std components. This scheme leverages standard atomic reference-counting (via shared_ptr<>)to provide automatic garbage collection.

The Case of The Unquoted Command Line: Process Monitor and MPGO.EXE

A few months ago I wrote about MPGO, a new Microsoft tool that ships with .NET 4.5 and enables profile-guided optimization of managed assemblies. Specifically, MPGO optimizes the layout of native images for managed assemblies, which reduces startup times, working set sizes, and page fault costs.

Shameless plug: Pro .NET Performance has a large section dedicated to improving startup performance, and I’ve written about this before: Using Prefetch to improve startup performance, Rebasing and compression.

Anyway, I was experimenting with MPGO and encountered a strange error when working with some of my assemblies. Specifically:

C:\Temp\mpgo test>mpgo -scenario App.exe -assemblylist App.exe -OutDir .

Error:  Timeout or error when trying to instrument assembly C:\Temp\mpgo test\App.exe (FFFFFFFF)
Profile information will not be collected for this assembly.
This will not prevent information from being collected for other assemblies

Error:  Timeout or Error when trying to remove instrumented assembly C:\Temp\mpgo test\App.exe (FFFFFFFF)
Failed to merge collected profile data into assembly C:\Temp\mpgo test\App.exe:
Unexpected Internal Exception The file "C:\Temp\mpgo test\App.ibc" does not exist

This error struck me as odd, because the application in question was really simple, and I certainly didn’t know what error FFFFFFFF meant. I tried specifying the full path to the executable, and got a different error instead:

C:\Temp\mpgo test>mpgo -scenario "C:\temp\mpgo test\App.exe" -assemblylist "C:\temp\mpgo test\App.exe" -OutDir .

Session executable does not appear to exist.

This produced a somewhat simpler error, although still completely misleading because App.exe exists in the specified directory. However, because the full path changed MPGO’s behavior, I suspected that something in its file access code or command-line parsing has gone awry.

This is where I launched Process Monitor and configured it to watch all events generated by MPGO.EXE. When using the latter command line, I saw very quickly that MPGO was trying (and failing) to access “C:\Temp\mpgo”, which is a directory that doesn’t exist—I explicitly gave it “C:\Temp\mpgo test\App.exe” as a parameter!

At this point I just had to look at the call stack to see what’s going on. MPGO.EXE is a managed application, but Process Monitor can’t give you managed call stacks (yet?), so I had to attach WinDbg and !u the raw addresses to see where the file access was coming from.

image

image

0:000> !u 0x600f8b
Normal JIT generated code
MPGO.Harness.PreRunValidation()
Begin 00600e10, size 22d
00600e10 55              push    ebp
00600e11 8bec            mov     ebp,esp
…snipped…
00600f7e 8b4e04          mov     ecx,dword ptr [esi+4]
00600f81 ba01000000      mov     edx,1
00600f86 e8051e7f59      call    mscorlib_ni+0x2f2d90 (59df2d90) (System.IO.File.InternalExistsHelper(System.String, Boolean), mdToken: 06004402)
00600f8b 85c0            test    eax,eax
00600f8d 7541            jne     00600fd0
00600f8f b9fc432a00      mov     ecx,2A43FCh (MT: MPGO.MpgoException)
00600f94 e88310c9ff      call    0029201c (JitHelp: CORINFO_HELP_NEWSFAST)
…snipped…

Next, I turned to the PreRunValidation method in Reflector and discovered that the exception is thrown because MPGO thinks my executable file does not exist, from a line that looks like this:

if (!File.Exists(this.Exe))
{
  MpgoException.Throw("Err_ExeMissing");
}

By inspecting all assignments to this.Exe, I found the following in the Harness class constructor:

Match match = Regex.Match(args[i], "(?<exe>(?:\"[^\"]+\")|[^ ]+)(?: (?<args>.*))?");
if (!match.Success)
{
    Usage.Show("Err_CantParseScenario_0", args[i]);
}
this.Exe = match.Groups["exe"].ToString();
if (this.Exe.StartsWith("\""))
{
    this.Exe = this.Exe.Trim(new char[] { '"' });
}
this.Exe = Path.GetFullPath(this.Exe);
this.Args = match.Groups["args"].ToString();

When applied to a quoted path, such as “C:\temp\mpgo test\App.exe”, this code produces an unquoted executable name and considers everything that follows the space to be the executable’s arguments…

There is a different bug when using the former command line. In that case, I configured Process Monitor to log process (and thread) creation/deletion events, and noticed that MPGO.EXE launches NGEN.EXE with an invalid command line:

image

The full command line is:

"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen.exe" install C:\Temp\mpgo test\App.exe /tuning /ExeConfig:C:\Temp\mpgo test\App.exe

…which confuses NGEN, because it treats “C:\Temp\mpgo” as the application name and the rest is an invalid command line. This time, the problem is that when launching NGEN, MPGO does not bother to quote the application name.

To summarize: the purpose of this post is not to bash MPGO—the bug has been reported to the team responsible and will likely be fixed in the next Visual Studio 11 drop. What I wanted to show is that Process Monitor is quite useful in determining why applications you aren’t familiar with are behaving incorrectly. Also, figuring out proper quoting of command line parameters is really nasty (on Windows).


I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn

Deep Dive into WinRT: MSDN Session

Thanks for coming to my session on WinRT internals today at Microsoft Raanana! Preparing for this session has been very interesting for me, especially as I was mucking around with vtable pointers for the Pro .NET Performance book anyway :-)

In this session we talked about the following:

  • Refreshment of how COM objects work
  • WinRT object layout and relationship to COM
  • The WinRT type system and threading model
  • Asynchronous operations in WinRT
  • Windows metadata files and projecting WinRT APIs to C#, C++/CX and JavaScript
  • Designing and developing WinRT components
  • Performance interoperability tips for WinRT
  • Profiling WinRT applications with Visual Studio Profiler

Here’s my favorite slide—as close to assembly language as they let me:

image

You can download the slides (PDF) and demos right now; the session’s video recording (Hebrew) will be available later on Channel 9.


I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn

Restoring a Computer From Windows Home Server Backup

The other day I had the immensely fun experience of restoring my Alienware m15x laptop from backup. It’s the second time I’ve restored a computer from backup since I have my trusty Acer easyStore Windows Home Server system. It just sits quietly in the corner, gathering dust and backing up my documents, work, and memories, claiming no reward but an additional 2TB hard drive every six months.

The general restore process is very simple:

  1. Burn a copy of the Windows Home Server Computer Restore CD
  2. Boot the faulty machine from the CD
  3. Let it find your home server over the network
  4. Choose which machine to restore and which backup to use
  5. Wait a few hours and you have a restored machine

The only potential pitfall in this process is that you need the restore CD environment to recognize your hardware. At the very least, it must be able to recognize the hard drive and the Ethernet network card, or it won’t be able to download the backup from your Home Server and restore the system from it.

With every backup, Windows Home Server captures the set of critical drivers required for the restore. Before restoring the system, you can get these drivers from the Home Server backup—they will be in a folder called Windows Home Server Drivers for Restore on your system drive when you view the Home Server backup from the Windows Home Server console. These drivers will work great in the recovery environment if you are restoring a 32-bit system—the recovery environment is 32-bit.

Unfortunately, if you are restoring a 64-bit system, you will need to find 32-bit drivers for the hard drive and network card manually. This can be a rather tedious process. You can usually find drivers on the hardware manufacturer’s website.

When restoring my Alienware m15x, the only hardware device with a missing driver was the Intel Ethernet NIC. You’ll need the Windows Vista 32-bit drivers, as that’s what the recovery environment is based on. Download them from here and you’ll be good to go!

Oh, and by the way—backups are important, but they are worthless if you never try restoring from backup. You’d think it should only take an hour and then spend a whole weekend sorting out driver problems, like I did :-)


I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn

Honored to be Renominated as Microsoft MVP for 2012

On April 1 (yes, it has the potential of being an April Fool’s every time!) I received the renomination letter—I am honored to receive the Microsoft MVP Award in Visual C# for 2012.

image

As I wrote a year ago, 2011 was an exciting year for C#—I had several opportunities to talk about async methods and the parallelism revolution last year, and 2012—the year of Windows 8—promises to be even more interesting for C# as we tackle the development of Metro-style apps.

I wouldn’t be writing this post if it weren’t for the help and support of my colleagues, friends, and managers at SELA and our business partners and friends at Microsoft Israel. Specifically, David Bassa and Ishai Ram are still the best managers and friends a tech professional can have, and Guy Burstein of Microsoft DPE continuously amazes me by shaping the Israeli developer community with MSDN events and user group meetings.

Thanks for reading—I am looking forward for the rest of 2012 and hope to continue providing you with interesting information on gory CLR internals and debugging problems :-)


I am posting short updates and links on Twitter as well as on this blog. You can follow me: @goldshtn

What AnyCPU Really Means As Of .NET 4.5 and Visual Studio 11

The 32-bit and 64-bit development story on Windows seemingly never stops causing problems for developers. It’s been a decade since 64-bit processors have started popping up in the Windows consumer environment, but we just can’t get it right. If you forget some of the gory details, here are a couple of reminders:

  • On a 64-bit Windows system, both the 32-bit and 64-bit versions of system DLLs are stored. The 64-bit DLLs are in C:\Windows\System32, and the 32-bit DLLs are in C:\Windows\SysWOW64.
  • When a 32-bit process opens a file in C:\Program Files, it actually reads/writes to C:\Program Files (x86).
  • There are separate views of (most of) the registry for 32-bit and 64-bit applications. You can change the 64-bit registry location and it wouldn’t be visible to 32-bit applications.

These differences are hardly elegant as they are, but they allow 32-bit applications to run successfully on a 64-bit Windows system. While unmanaged applications always had to choose the native target—x86, x64, or ia64 in the Visual Studio case—managed code has the additional choice of AnyCPU.

What AnyCPU used to mean up to .NET 4.0 (and Visual Studio 2010) is the following:

  • If the process runs on a 32-bit Windows system, it runs as a 32-bit process. IL is compiled to x86 machine code.
  • If the process runs on a 64-bit Windows system, it runs as a 64-bit process. IL is compiled to x64 machine code.
  • If the process runs on an Itanium Windows system (has anyone got one? ;-)), it runs as a 64-bit process. IL is compiled to Itanium machine code.

Prior to Visual Studio 2010, AnyCPU was the default for most .NET projects, which was confusing to some developers: when they ran the application on a 64-bit Windows system, the process was a 64-bit process, which may cause unexpected results. For example, if the application relies on an unmanaged DLL of which only a 32-bit version is available, its 64-bit version won’t be able to load that component.

In Visual Studio 2010, x86 (and not AnyCPU) became the default for most .NET projects—but otherwise the semantics haven’t changed.

In .NET 4.5 and Visual Studio 11 the cheese has been moved. The default for most .NET projects is again AnyCPU, but there is more than one meaning to AnyCPU now. There is an additional sub-type of AnyCPU, “Any CPU 32-bit preferred”, which is the new default (overall, there are now five options for the /platform C# compiler switch: x86, Itanium, x64, anycpu, and anycpu32bitpreferred). When using that flavor of AnyCPU, the semantics are the following:

  • If the process runs on a 32-bit Windows system, it runs as a 32-bit process. IL is compiled to x86 machine code.
  • If the process runs on a 64-bit Windows system, it runs as a 32-bit process. IL is compiled to x86 machine code.
  • If the process runs on an ARM Windows system, it runs as a 32-bit process. IL is compiled to ARM machine code.

The difference, then, between “Any CPU 32-bit preferred” and “x86” is only this: a .NET application compiled to x86 will fail to run on an ARM Windows system, but an “Any CPU 32-bit preferred” application will run successfully.

To inspect these changes, I created a new C# console application in Visual Studio 11 that prints the values of Environment.Is64BitOperatingSystem and Environment.Is64BitProcess. When I ran it on my 64-bit Windows system, the result was as follows:

Is64BitOperatingSystem = True
Is64BitProcess         = False

Inspecting the project’s properties shows the following (in the current Visual Studio UI “Prefer 32-bit” is grayed out and unchecked, where in actuality it is enabled…):

image

Inspecting the executable with CorFlags.exe shows the following:

Version   : v4.0.30319
CLR Header: 2.5
PE        : PE32
CorFlags  : 131075
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 1
Signed    : 0

After changing the 32BITPREF setting with CorFlags.exe (using the /32bitpref- option), the output was as follows:

Is64BitOperatingSystem = True
Is64BitProcess         = True


I am posting short updates and links on Twitter as well as on this blog. You can follow me:@goldshtn