Hi,

I tried your projects, and got somewhat different results (on an iPad2).

Objective-C implementation: 0,296s
MonoTouch (release mode): 0,677s
MonoTouch (release mode, with LLVM enabled): 0,397

So just MonoTouch release mode is 2.3x times slower, but once you enable
LLVM, this goes down to 1.34x slower.

I also noticed that BitmapContext.FillRect is called a lot (39635 times),
so I commented it out and now I get these timings:
Objective-C implementation: 0,224s
MonoTouch (LLVM enabled): 0,293s

So just calling FillRect 39635 times takes 0,072s in ObjC and 0,104s with
MonoTouch - the discrepancy is due to the fact that the MonoTouch version
obviously has to do more work (it has to do a managed-to-native transition
(and back again)). So now MonoTouch is 1.31x slower.

The point is that LLVM mode is exactly for this kind of cpu intensitive
tasks, since our jit doesn't generate as optimized code as the LLVM one can.

Now I started looking a bit deeper, and realized that the loop in
IsInMandelbrotSet loops 100 times in the MonoTouch version and only 50
times in the ObjC version. Redoing the tests in MonoTouch, but this time
only looping 50 times, I get this:

MonoTouch (LLVM enabled): 0,290s.

Yes, that's correct. The MonoTouch (with LLVM) version is actually 1% *
faster* than the ObjectiveC version with identical code.

And as shown this difference can probably be increased (by not calling
FillRect 40k times, but perhaps manually create the bitmap in managed
memory and then draw the bitmap with one call - this change would likely
benefit both implementations, but it would benefit MonoTouch most).

I hope this helps :)

Rolf

On Wed, Feb 15, 2012 at 10:14 AM, RoyCornelissen <[email protected]>
wrote:
> Hi,
>
> Just as a little exercise I decided to try out a Mandelbrot test in
> MonoTouch just to have a look at performance. I took this Objective-C
> implementation  https://github.com/ddeville/Mandelbrot-set-on-iPhone on
> GitHub  as a basis and ported the implementation of the view 1-to-1 to
> MonoTouch. Because of some differences in API not all of the code is 100%
> the same, and I'm no CoreGraphics expert, but as far as I know this looks
> OK. The MonoTouch implementation can be found here
> http://dl.dropbox.com/u/1135505/MonobrotSet.zip
>
> Now when I run this on my iPhone, the MonoTouch version is 2.8 times
slower
> than the Objective-C version, specifically the part where the Mandelbrot
Set
> is drawn in the bitmap. Objective-C takes ~0.99 seconds, MonoTouch ~2.8
> seconds.
>
> Can anyone help explain where the overhead is coming from? Is there
anything
> I could have done to make this faster given the reference implementation
in
> Objective-C? I'm not looking for a faster Mandelbrot algorithm but merely
> trying to explain what is making the big difference. Or did I make a
mistake
> in translating the Objective-C code to MonoTouch?
>
> Here's the C# code that does the work, I tried to stay as close as
possible
> to the Objective-C implementation of the view
>
https://github.com/ddeville/Mandelbrot-set-on-iPhone/blob/master/Classes/MandelbrotView.m
> (link)
>
>        [Register("MandelbrotView")]
>        public class MandelbrotView: UIView
>        {
>                private const int MANDELBROT_STEPS = 50;
>
>                public MandelbrotView ()
>                {
>                        Initialize();
>                }
>
>                public MandelbrotView(IntPtr handle): base (handle)
>                {
>                        Initialize();
>                }
>
>                public override void Draw (System.Drawing.RectangleF rect)
>                {
>                        DateTime reference = DateTime.Now;
>
>                        // get an image representation of the bitmap
context
>                        var image = _bitmapContext.ToImage();
>
>                        // draw the image in the current context
>                        var context = UIGraphics.GetCurrentContext();
>                        context.DrawImage(rect, image);
>
>                        // release the image
>                        image.Dispose();
>
>                        Console.WriteLine("draw rect duration = {0}",
(DateTime.Now -
> reference).TotalMilliseconds / 1000);
>                }
>
>                private CGBitmapContext _bitmapContext;
>
>                private void Initialize ()
>                {
>                        Console.WriteLine("MonoTouch Mandelbrot
implementation");
>                        var reference = DateTime.Now;
>
>                        // instantiate the bitmap context
>                        _bitmapContext =
CreateCustomBitmapContextWithSize(new SizeF(480.0f,
> 320.0f));
>
>                        Console.WriteLine("bitmap context creation
duration = {0}", (DateTime.Now
> - reference).TotalMilliseconds / 1000);
>                        reference = DateTime.Now;
>
>                        // draw the Mandelbrot Set
>                        var center =  new PointF(this.Center.Y,
this.Center.X);
>                        DrawMandelbrot(center, 1);
>
>                        Console.WriteLine("drawing mandelbrot in bitmap
duration = {0}",
> (DateTime.Now - reference).TotalMilliseconds / 1000);
>                }
>
>                private CGBitmapContext
CreateCustomBitmapContextWithSize(SizeF size)
>                {
>                        CGBitmapContext context = null ;
>
>                        var bitmapBytesPerRow = (size.Width * 4) ;
>                        bitmapBytesPerRow += (16 -
bitmapBytesPerRow%16)%16 ;
>
>                        var bitmapByteCount = (bitmapBytesPerRow *
size.Height) ;
>
>                        CGColorSpace colorSpace =
CGColorSpace.CreateDeviceRGB();
>
>                        var bitmapData = new byte[(int) bitmapByteCount];
>
>                        context = new CGBitmapContext(bitmapData, (int)
size.Width, (int)
> size.Height, 8, (int) bitmapBytesPerRow, colorSpace,
> CGBitmapFlags.PremultipliedLast);
>
>                        if (context == null)
>                        {
>                                bitmapData = null;
>                                Console.WriteLine("Context not created!");
>                                return null;
>                        }
>
>                        return context;
>                }
>
>
>                private void DrawMandelbrot(PointF center, float zoom)
>                {
>                        _bitmapContext.SetAllowsAntialiasing(false);
>                        _bitmapContext.SetRGBFillColor(0.0f, 0.0f, 0.0f,
1.0f);
>
>                        float re;
>                        float im;
>
>                        // mapping the bounding box to pixels
>
>                        // zoom 1 has to be between -2 and 1 and -1 to 1
>                        // any additional zoom divides these by the zoom
>
>                        // loop through every pixel of the frame...
>                        for (int i = 0 ; i < 480 ; i++)
>                        {
>                                for (int j = 0 ; j < 320 ; j++)
>                                {
>                                        re = (((float)i - 1.33f *
center.X)/160) ;      // -2 to 1      -       screen width  =
> 480
>                                        im = (((float)j - 1.00f *
center.Y)/160) ;      // -1 to 1      -       screen height =
> 320
>
>                                        re /= zoom ;
>                                        im /= zoom ;
>
>                                        if (IsInMandelbrotSet(re, im))
>                                        {
>
 _bitmapContext.FillRect(new RectangleF(i, j, 1.0f, 1.0f));
>                                        }
>                                }
>                        }
>                }
>
>                private bool IsInMandelbrotSet(float re, float im)
>                {
>                        float x = 0 ;   float nx ;
>                        float y = 0 ;   float ny ;
>                        bool fl = true;
>                        for(int i = 0 ; i < MANDELBROT_STEPS ; i++)
>                        {
>                                // We calculate the real part of the
sequence
>                                nx = x*x - y*y + re ;
>                                // We calculate the imaginary part of the
sequence
>                                ny = 2*x*y + im ;
>                                // We compute the magnitude at each step
>                                // We check if it's greater than 2
>                                if((nx*nx + ny*ny) > 4)
>                                {
>                                        fl = false ;
>                                        break ;
>                                }
>                                x = nx ;
>                                y = ny ;
>                        }
>
>                        return fl ;
>                }
>        }
>
> Thanks, Roy
>
> --
> View this message in context:
http://monotouch.2284126.n4.nabble.com/Why-is-the-MonoTouch-version-of-this-Mandelbrot-Set-test-2-8-times-slower-tp4389869p4389869.html
> Sent from the MonoTouch mailing list archive at Nabble.com.
> _______________________________________________
> MonoTouch mailing list
> [email protected]
> http://lists.ximian.com/mailman/listinfo/monotouch
_______________________________________________
MonoTouch mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/monotouch

Reply via email to