[IronPython] Optimized methods and serious performance issues

Dino Viehland dinov at exchange.microsoft.com
Thu May 25 18:45:58 CEST 2006


This common idiom actually works against our reflect optimization of built-in methods, but we still make it work.

Just to give you (and anyone else curious) an overview of this:  We have a piece of code called the ReflectOptimizer which generates an optimized call to .NET methods.  The way it does this is it generates code for doing type checks for all the possible overloads of a method and emits that all into one method.  Then when you call from Python we dispatch to this helper method, which can do a bunch of efficient type checks, and finally dispatch to the correct method.

Creating these methods isn't cheap, so we defer this until the first invocation of a method.  At that point in time we replace the callers method (in whatever dictionary they were in) with the new optimized method.

When someone follows the common idiom we cannot successfully back patch the reference to the method, so instead the non-optimized method needs to remember that it's been optimized and use the optimized method instead.  Eventually the local copy will go out of scope, and we'll be left w/ only the optimized version.

The back-patching is what's potentially problematic: If we get that back-patching wrong then we'll continuously re-optimize methods over and over again.  That obviously kills performance, which is what I suspect is going on here.

Now strangely enough because the work we do to make this common idiom still be efficient this could actually be a way to work around the back-patching bug, if that is indeed what we're seeing.

________________________________________
From: users-bounces at lists.ironpython.com On Behalf Of J. Merrill
Sent: Thursday, May 25, 2006 9:29 AM
To: Discussion of IronPython
Subject: Re: [IronPython] Optimized methods and serious performance  issues

I know almost nothing about DirectX, am definitely not a Python guru, and have not experimented with IP in this area.  However, my impression is that there is a common Python "idiom" for speeding up method calls, which is to use a variable (often a local) to hold a reference to a "bound method" and make calls through that variable.  This avoids all the work that normally has to be done to figure out what actual method (the one associated with the instance, the class, the parent class, the parent class's parent, etc etc) is supposed to be called by a particular "callable" expression.

Whether this is appropriate in your case, I can't say.  For example, if the value of self.mesh can change while your loop is running, it won't give the right results to do
    methref = self.mesh.DrawSubset
and then call
    methref(0)
in your loop, because this will call via whatever value mesh had been when you set methref.

If it's appropriate, have you tried that technique?

At 11:33 AM 5/25/2006, Jonathan Jacobs wrote
>(Please disregard any earlier message about this, I think I might have pressed
>"Send" accidentally.)
>
>Hi,
>
>I ran across some "interesting" behaviour today.
>
>Short version:
>I have a handful of Direct3D.Mesh objects (courtesy of Direct3D.Mesh.Teapot)
>which I render using self.meshInstance.DrawSubset(0). I've been experiencing
>pretty serious performance issues, so I did a bit of testing and this is what
>I came up with:
>
>(The averages are accumulated every call and averaged (and output) every 500
>calls, a small value is obviously better, all values are in milliseconds.)
>
>No drawing calls:
>running average: 0.0236448413598 ms
>running average: 0.0229452898402 ms
>running average: 0.0236400825059 ms
>running average: 0.0257713352135 ms
>
>No drawing calls, -X:NoOptimize:
>running average: 0.0251883756139
>running average: 0.0250299057799
>running average: 0.0224732115359
>running average: 0.0225412631463
>
>self.mesh.DrawSubset(0):
>running average: 3.40948918622 ms
>running average: 3.45289207504 ms
>running average: 3.43480367147 ms
>running average: 3.45502784866 ms
>
>self.mesh.DrawSubset(0), -X:NoOptimize:
>running average: 0.111673644441 ms
>running average: 0.118880928633 ms
>running average: 0.134856876975 ms
>running average: 0.11670232533 ms
>
>Helper.DrawMesh(self.mesh, 0):
>running average: 0.0415348007294 ms
>running average: 0.0328241945979 ms
>running average: 0.0296612223703 ms
>running average: 0.0330559507815 ms
>
>Helper.DrawMesh(self.mesh, 0), -X:NoOptimize:
>running average: 0.063753413583 ms
>running average: 0.0668509515698 ms
>running average: 0.0603922350916 ms
>running average: 0.070181197511 ms
>
>Helper.DrawMesh is my own function implemented in C#:
>public class Helper {
>   public static void DrawMesh(Microsoft.DirectX.Direct3D.Mesh mesh, int id) {
>     mesh.DrawSubset(id);
>   }
>}
>
>I'm interested as to why the self.mesh.DrawSubset call is so disappointingly
>slow and why it is sped up by *disabling* method optimization.
>
>Unfortunately, it is laborious for me to separate the useful code from the
>not-so-useful code and I'm not sure how to reproduce this outside of DirectX.
>I can take some time out to try and cut this down to the bare essentials if
>need be.
>
>Regards
>--
>Jonathan
>
>When you meet a master swordsman,
>show him your sword.
>When you meet a man who is not a poet,
>do not show him your poem.
>                 -- Rinzai, ninth century Zen master


J. Merrill / Analytical Software Corp


_______________________________________________
users mailing list
users at lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



More information about the Ironpython-users mailing list