Efficiency/Compilation

Jan 15, 2010 at 3:37 PM

I suspect I'll have to write this in c# in order to get the desired speed but here it goes! So, I would like to invoke .net methods and find properties using reflection. i.e. call objectInstance.getType()  instead of having to supply it. So I looked at your code and wrote an equivalent for GetTypeFast in ClrGenerators. I do plan to hash the function , but right now im looking at raw speed. The test function below on my computer takes

3.298 seconds for 10,000 get-type-fast calls. Is there any way to speed this up? I've also tried to use the 'compile' function which i suspect would speed things up drastically, but when i use it I see no .fasl file. Ive also attempted to convert it to a library and then use comipile and compile->closure. In each instance i get an error 'top-level program is missing an import statement. ' So i guess i cannot compile a library???

For comparison, I found the speed for it written in c#.  It accomplished the same task in .107 seconds.

(import (rnrs) (ironscheme clr))

(define (manifest-module-name assembly)
  (clr-prop-get System.Reflection.Module Name
        (clr-prop-get System.Reflection.Assembly
                  ManifestModule assembly)))


(define-syntax block
  (syntax-rules ()
    ((_ name body ...) (call/cc (lambda (name) body ...)))))


(define (get-assemblies)
  (clr-call AppDomain GetAssemblies (clr-static-prop-get AppDomain CurrentDomain)))


(define (get-type-fast name)
  (block out
     (vector-for-each
      (lambda (assembly)
        (when (not (string=? (manifest-module-name assembly) "<In Memory Module>"))
          (let ((type (clr-call Reflection.Assembly GetType assembly name)))
            (if (not (null?  type)) (out type)))))
     (get-assemblies))

     #f))
(define (test)
  (let f ((i 0))
     (get-type-fast  "System.Reflection.Module")
     (if (< i 10000)
       (f (+ 1 i)))))

 

 

C# code

public static Type GetTypeFast(string name)
        {
            foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (ass.ManifestModule.Name != "<In Memory Module>")
                {
                    var t = ass.GetType(name);
                    if (t != null)
                    {
                        return t;
                    }
                }
            }
            return null;
        }

        static void Main(string[] args)
        {
            /* Read the initial time. */
            DateTime startTime = DateTime.Now;
            Console.WriteLine(startTime);

        
            for (int i = 0; i < 10000; i++)
            {
                GetTypeFast("System.Reflection.Module");

            }


            /* Read the end time. */
            DateTime stopTime = DateTime.Now;
            Console.WriteLine(stopTime);

            /* Compute the duration between the initial and the end time. */
            TimeSpan duration = stopTime - startTime;
            Console.WriteLine(duration);

            Console.ReadKey();
         
        }

 

Coordinator
Jan 15, 2010 at 4:36 PM

CALL/CC is your problem here. Calling it 10000 times is like throwing and catching 10000 exceptions.

Also, if you were running this under the debugger, it would be even worse.

Try rewriting the iteration without CALL/CC and you will see how much faster it be  :)

Jan 15, 2010 at 5:34 PM
Edited Jan 15, 2010 at 5:35 PM

Beautiful: only .280 seconds!

(define (get-type-fast name)
  (let* ((assemblies (get-assemblies)) (length (vector-length assemblies)))
    (let f ((assembly (vector-ref assemblies 0)) (i 0))
      (if  (< i length)
       (if (not (string=? (manifest-module-name assembly) "<In Memory Module>"))
           (let ((type (clr-call Reflection.Assembly GetType assembly name)))
              (if (null? type) (f (vector-ref assemblies (+ i 1)) (+ i 1)) type))
           (f (vector-ref (vector-ref assemblies (+ i 1)) (+ i 1))))
       #f ))))

Arg.. not so beatiful code X)

 

Any way to speed this up even more?

 

Coordinator
Jan 15, 2010 at 6:03 PM

Mush better :)

You might let it look better using the DO construct.  It's a hard to remember one.

You can use (AND something then) instead of (IF something then #f).

Speed-wise, you can try using FX+ and FX<? (or using (ironscheme unsafe) $FX+ and $FX<?). Not sure it will much difference though.

IMO this is 'close' enough to a 'professional' .NET language.

 

Jan 15, 2010 at 8:15 PM
Edited Jan 15, 2010 at 8:35 PM

I have been thwarted be scheme.

(let hi ((return? #f) (value #f)) (if (not (eqv? #f return?)) value (begin (hi 2 #t) 3))) returns 3 not 2. There goes my attempt at creating a goto statement without continuations.

I think scheme needs to include an efficient goto/tagbody. Oh well.

 

And yeah, .2 seconds is about as fast as it got. It changes between .18 and .28.

Edit: oh right, the recursion unwinds. Oh well.

 

Coordinator
Jan 16, 2010 at 1:18 PM

Try increasing the iterations to say 100 000 or more to get a better timing.

You can use (time <expr>) in IronScheme (and most other Schemes). This uses the same hires timer as the Stopwatch class.

Coordinator
Jan 16, 2010 at 1:23 PM
Edited Jan 16, 2010 at 1:24 PM
Suroy wrote:
I've also tried to use the 'compile' function which i suspect would speed things up drastically, but when i use it I see no .fasl file. Ive also attempted to convert it to a library and then use comipile and compile->closure. In each instance i get an error 'top-level program is missing an import statement. ' So i guess i cannot compile a library???

Compiling (using COMPILE) only works on a program's libraries/dependencies. Same for COMPILE->CLOSURE.

This is not really compiling, but the full expansion up to the point of actual compilation serialized and ready for compilation.