C#/.Net JIT on difference versions of Windows

Go To StackoverFlow.com

0

I've been working on a lot of C#/.Net code recently, and noticed something (potentially) strange.

The team I'm in is developing using Windows 7 Professional and Visual Studio 2008 (for what it's worth), and when some of the code produced is run on different versions of windows (in my example, Windows XP Professional with .Net 3.5 installed) we get some slightly strange behaviour.

What I've noticed is a very specific set of nested ifs (that each call the same method, but with different parameters), within a switch block seems to be behaving differently at run-time on one specific machine than it is on the development machines. An example of what I mean is this:

switch (someVariable)
{
    case true:
        //do some stuff
        //this case seems fine when stepped through
        break;
    case false:
        //do some stuff
        //this is the case that causes problems
        if (Foo())
        {
            if(Bar())
            {
                someOtherMethod();
                //I'll call these the nested ifs
                if (object.SomeValue == targetValueOne)
                    FooBar(string, someParam, int anotherParam);
                if (object.SomeValue == targetValueTwo)
                    FooBar(string differentStrParam, int differentIntParam);
                else
                    FooBar(string thirdStrParam, int thirdIntParam);
            }
        }
        else
        {
           //do some different things
        }
        break;
}

The example is overly complicated, but it still holds (pretty much) true to the code I have in front of me (there are extra if's to check object.SomeValue's value).

On the Windows 7 (development) machines, the code runs perfectly - I've stepped through it with each permutation of object.SomeValue and each code path is executed as planned. However, when this code is run on a Windows XP (belonging to a tester) machine, the nested ifs don't seem to even get called, especially when Bar() returns true.

There are two versions of FooBar(), one that returns and one that doesn't. I'm explicitly calling the version that doesn't, here.

Foo() and Bar() are two different set-up methods, if they complete the set-up steps then they return true, otherwise they return false.

As I've said above, When this code is run on the tester's machine, the nested ifs are skipped entirely. Whereas they are evaluated correctly on the development machines. I know that the JIT compiles to native code at run time, and that native code is specific for the machine that it's running on.

So, I guess I'm asking if anyone knows whether it could be the JIT on the tester's machine is what's causing these nested ifs to be skipped, or whether I've missed something out? Or could the JIT compiler be trying to optimise this block and producing code that doesn't actually perform the way it's supposed to?

Maybe a clearer example:

switch (Hawrdware.SomeProperty)
{
  case true:
      //do some stuff
      //this case seems fine when stepped through
      break;
  case false:
    //do some stuff
    //this is the case that causes problems
    if (SetupHardware()) //calls our library functions
    {                    //these have been tested thoroughly
      if(WaitForCorrectResponse()) //waits for the correct post-setup
      {                            //message from the hardware
        SendOTAMessageFromHardware(string message);
        //I'll call these the nested ifs
        if (Hawrdware.PropertyOne == targetValueOne)
            SendOTAMessageFromHardware(string message, int timeOutForResponse);
        if (Hawrdware.PropertyTwo == targetValueTwo)
            SendOTAMessageFromHardware(string message, int timeOutForResponse);
        else
            SendOTAMessageFromHardware(string message, int timeOutResposnse);
      }
    }
    else
    {
       //do some different things
    }
    break;
}

public void SendOTAMessage(string message)
{
  if (message != null)
  {
    device.Write(message);
    //Hardware's on-board OS takes care of the rest
  }
}

public void SendOTAMessage(string message, int TimeOut)
{
  if (message != null)
  {
    StopWatch clock = new StopWatch();
    device.Write(message);
    //Hardware's on-board OS takes care of the rest

    while (time.Elapsed.TotalSeconds < TimeOut)
    {
      //wait and see if we get a response
      //if we do, store it in a string (legacy
      //reasons state we have to do this
    }
  }
}

public string SendOTAMessage(string message, int TimeOut)
{
  if (message != null)
  {
    StopWatch clock = new StopWatch();
    device.Write(message);
    //Hardware's on-board OS takes care of the rest

    while (time.Elapsed.TotalSeconds < TimeOut)
    {
      //wait and see if we get a response
      //if we do, return this message as a string
    }
  }
}
2012-04-04 08:19
by Jamie Taylor
The JITter compiles to native code from bytecode (CIL). Also, to your last sentence - you're probably going to have to come up with a (minimal) example you can show us, if we're to help - AakashM 2012-04-04 08:25
I think you might be barking up the wrong tree here. Are you compiling against the same framework version on both XP and Win7? Do you have a different Win7 machine to test on? Is there anything environment specific that is accessed in Foo or Bar - Slugart 2012-04-04 08:27
Might be a JIT bug in the 3.5 runtime that was fixed in the 4.0 runtime. I suspect this isn't related to the choice of OS. Another issue is that you can't conclude from step-through not reaching something, that it doesn't get executed. It might be a debugger issue - CodesInChaos 2012-04-04 08:30
@Slugart: Foo send specific set-up commands to a piece of attached hardware, and Bar enters a loop until the device responds to those set-up commands with the correct responses (or until a time-out is reached). both are using our custom library to communicate with the hardware. AFAIK, we're all using the same version of the framework as the tester's machine, too. the only (major) thing that differentiates the development machines from the tester's machine is the Operating System version -aside from the underlying hardware of the machines. Could that cause a problem - Jamie Taylor 2012-04-04 08:32
Most probably this is going to be a problem either with how the OS interfaces with your hardware or a logic problem. Try building on Win7 and running on XP ;) As AakashM mentioned the JITter compiles to native code - Slugart 2012-04-04 08:34
@Slugart: I should have mentioned that's one of the ways we're testin - Jamie Taylor 2012-04-04 08:47
@AkashM: Just spotted that, thanks. I've edited my OP to reflect tha - Jamie Taylor 2012-04-04 08:48
If you're suspicious about JIT optimization having an impact you can disable it: http://msdn.microsoft.com/en-us/library/9dd8z24x.aspx. I'd be surprised if this was actually the problem, though.. - Ian Gilroy 2012-04-04 09:18


0

You need to rule out every other possible factor, unless you've got something more conclusive than "My if statement never gets hit in the debugger".

Build two identical machines:

  • One using the 'suspect' OS version, the other using the version in Dev. Both should be on the same 'bitness' for initial testing - i.e if one is 32bit, the other must be 32bit too.
  • Ensure the new machines have the correct .NET Framework versions, third party libraries, software needed, etc.
  • Ensure they are patched from Windows Update.
  • Ensure that the external hardware drivers are installed, and are both the same version of driver. If the hardware vendor provides differing libraries/software based on OS, then you need to know why.
  • Ensure that the external hardware is attached correctly, has the same version(s) of software on both.
  • Ensure that the external hardware is attached identically. (Same port on the machines)
  • Ensure the external hardware is sending back identical responses on both (it may be possible that the external hardware behaves differently based on OS version)
  • Ensure that the same events are being triggered, in the same order, on the same threads.
  • Ensure that the same variables are set in the same state, when entering your method.

Throughout this testing, ensure that for EVERY action you perform on one, you perform identically on the other.

2012-04-04 08:51
by NoName


0

If you really suspect faulty compilation do the following:

  1. Trace the value of Hawrdware.SomeProperty just before the switch
  2. Add a trace inside the false switch case
  3. Add trace values inside SetupHardware and WaitForCorrectResponse.

If you see Hardware.SomeProperty==false + trace inside case statement but no trace inside the methods it might be right. No need to step through either, removing the debugger from the equation will only make things simpler.

2012-04-04 09:12
by Slugart
Ads