none
64 bit is slower than 32 bit for loading an assembly in runtime RRS feed

  • Question

  • When migrating from 32 bit windows to 64 bit windows I encountered degradation in performance relating to an assembly which is dynamically loaded during runtime.

    The degradation happens once when I load the assembly and assign the delegates. It takes nearly half a minute on the 64 bit – instead of instantly on the 32 bit. Afterwards it runs smoothly.

    I suspect it has something to do with a "just in time" compilation of the dll which was built with "Any CPU" –

     How can I make it run faster?

    (the slow code:

    Assembly TheAssembly = Assembly.LoadFile ("myAssembly");
    
    TheDelegate  delX1 = GetTheDelegate(TheAssembly, "X1");
    TheDelegate  delX2 = GetTheDelegate(TheAssembly, "X2");
    ......
    TheDelegate  delX20 = GetTheDelegate(TheAssembly, "X20");
    
    
    
    private TheDelegate GetTheDelegate(Assembly TheAssembly, string className)
    {
        MethodInfo meth = GetTheMethod(TheAssembly, className);
        return (meth != null) ? (TheDelegate)Delegate.CreateDelegate(typeof(TheDelegate), meth) : null;
    }
    
    private MethodInfo GetTheMethod(Assembly TheAssembly, string className)
    {
        Type[] typeArray = new Type[1];
    
        typeArray.SetValue(typeof(double[]), 0);
    
        Type t = TheAssembly.GetType(className);
    
        MethodInfo m = (t != null) ? t.GetMethod("TheMeth", typeArray) : null;
        return m;
    }
    

    Wednesday, August 22, 2012 3:18 PM

Answers

  • I am not sure how Dot Trace works, but normal profiler will show you everything, including native code (like CLR JIT). If that info is not available in your profiler (which would be quite surprising), use another one - I would personally recommend PerfView from Vance - start with his PerfView tutorial lessons.

    If it proves to be x64 JIT slowness, then you might try to split extremely large functions into smaller ones (e.g. 100 Add calls per method). Just splitting it in half might already show some improvement if it is indeed JIT that causes it.

    -Karel

    Saturday, August 25, 2012 4:40 PM
    Moderator
  • "There are about 15000 “Add“ lines like this that generate some XY experimental data tables."

    The problem is likely caused by JIT, the x64 JIT compiler is slower than the x86 one, especially for such methods.

    Saturday, August 25, 2012 9:09 AM
    Moderator
  • Thanks again Karel, Mike,

    I didn't know about PerfView - it is informative. It does show in the JIT stats that the InitCompoundTables  method has JIT time of 40000 msec. So it is indeed JIT that is the problem. I will try to either split them as you suggest Karel, or use an array initialization as Mike is suggesting.

    Sunday, August 26, 2012 10:04 AM

All replies

  • Run your app under a profiler and see where the time is spent. With 0s going to 30s I would guess some hash verification kick in in the OS (just a rough guess). Profiler should tell you more.

    -Karel

    Thursday, August 23, 2012 12:31 AM
    Moderator
  • You could ngen the assemblies on the 64-bit system to see if the time goes away.


    Phil Wilson

    Thursday, August 23, 2012 6:34 PM
  • Well, I took the advice about profiling and it turns out I was wrong. The bottleneck is somewhere else.

    I have a computer generated code file that I use to build some scientific chemistry tables. The method looks like this:

    namespace abc
    {
        public partial class Product
        {
    		CompTable A1 = new CompTable();
    		CompTable A2 = new CompTable();
                      .......
    		CompTable A25 = new CompTable();
        }
    }
    namespace abc
    {
        public partial class Product
        {
            private void InitCompoundTables()
            {
                A1.Add(-1.04537, 0.532); 
                A1.Add(-0.96891, 0.517); 
                A1.Add(-0.87906, 0.492); 
    			
    			.....
    	   A2.Add(-1.98797, 0.52); 
                A2.Add(-0.09, 0.17); 
                A2.Add(-0.87342523, 0.42); 
    			
    			......
    			
    	   A25.Add(-6.98797, 0.352); 
                A25.Add(-0.09, 0.6717); 
                A25.Add(-0.342523, 0.8942); 
    		
          }
    	
       }
    }	

    There are about 15000 “Add“ lines like this that generate some XY experimental data tables.

    When I run the program in debug mode and “step into” the InitCompoundTables method (which sits in a separate file) the computer hangs for the 30 seconds BEFORE it shows being positioned in the first line of the method. Once inside the method, when I click the green “continue” arrow of the debug – I get instant response running through the Add calls. Subsequent calls to the same  InitCompoundTables method are immediate. So it has to do with setting up the method for first time usage. It must be that each “Add” method call line requires some heavy duty initialization – though why it would I don’t know – and it certainly wasn’t like that in the 32 bit.

    Any ideas?


    Friday, August 24, 2012 2:35 PM
  • Still same answer - profiler will tell you more. What you used is debugger, that's not going to help you in this case.

    -Karel

    Friday, August 24, 2012 3:41 PM
    Moderator
  • "There are about 15000 “Add“ lines like this that generate some XY experimental data tables."

    The problem is likely caused by JIT, the x64 JIT compiler is slower than the x86 one, especially for such methods.

    Saturday, August 25, 2012 9:09 AM
    Moderator
  • Thanks Mike,

    I could tweak the code and make it into say  1 "Add" method call that will accept 1000 parameters with a "params" argument - instead of 1000 Add calls.

    Would that solve the problem?

    Saturday, August 25, 2012 1:55 PM
  • Thanks Karel,

    I used Dot Trace from Jet Brains.

    It showes the InitCompoundTables as being extremely slow - but when I drill down to see which line is the slow line - it showes all of them as fast. I think it doesn't capture the compilation phase.

    Saturday, August 25, 2012 2:16 PM
  • I did a test and it seems that params is not a good idea. Just allocate and initialize the array explicitly and pass it to an Add method that takes an array:

    double[] values = new[] { 1.0, 2.0, 3.0... };

    Add(values);

    When you do this the C# compiler does a trick to initialize the array very fast and with very few instructions. With params it falls back to the usual array initialization, element by element. That generates a ton of instructions and you end up with the same JIT problem.

    Saturday, August 25, 2012 2:30 PM
    Moderator
  • I am not sure how Dot Trace works, but normal profiler will show you everything, including native code (like CLR JIT). If that info is not available in your profiler (which would be quite surprising), use another one - I would personally recommend PerfView from Vance - start with his PerfView tutorial lessons.

    If it proves to be x64 JIT slowness, then you might try to split extremely large functions into smaller ones (e.g. 100 Add calls per method). Just splitting it in half might already show some improvement if it is indeed JIT that causes it.

    -Karel

    Saturday, August 25, 2012 4:40 PM
    Moderator
  • Thanks again Karel, Mike,

    I didn't know about PerfView - it is informative. It does show in the JIT stats that the InitCompoundTables  method has JIT time of 40000 msec. So it is indeed JIT that is the problem. I will try to either split them as you suggest Karel, or use an array initialization as Mike is suggesting.

    Sunday, August 26, 2012 10:04 AM
  • You could try to put those 15000 value-pairs into a file and read it using a simple loop-function, at least for me that seems to be a better solution. I know that file access is not the fastest but you surely will not wait for JIT to compile 15000 lines.

    Thursday, August 30, 2012 8:08 AM
  • Thanks pselmeczy

    I didn't do it by reading a file - for version control reasons. The tables change often  and the code changes often and I wanted to make sure I'm not reading an outdated file with a new code or vice versa. It seemed safer to have the tables as part of the code. I don't know if there is a way for a file to be part of the dll  - but if so that may also be a solution.

    Friday, August 31, 2012 6:51 AM