Click here to Skip to main content
15,032,755 members
Please Sign up or sign in to vote.
2.00/5 (1 vote)
I have been reading that unsafe is faster than Marshal.Copy,
but the next 2 codes show converse results:

Slower:
C#
unsafe
            {
                for (int i = 0; i < w * h * 3; i++)
                    ((byte*)data2.Scan0)[i] = this.bytes[alpha][i];
            }

Faster:
C#
Marshal.Copy(bytes[alpha], 0, data2.Scan0, bytes[alpha].Length);


Full code:
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace _123
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.DoubleBuffered = true;

            Create_Animation();
            this.Paint += Draw;

            timer1 = new Timer();
            timer1.Interval = 1;
            timer1.Enabled = true;
            timer1.Tick += Draw_Animation;
        }

        int w;
        int h;

        Byte[][] bytes;

        private void Create_Animation()
        {
            //w = System.Windows.Forms.Screen.GetBounds(this).Width;
            //h = System.Windows.Forms.Screen.GetBounds(this).Height;
            
            w = 1000;
            h = 1000;

            bitmap1 = new Bitmap(w, h);
            bytes = new Byte[256][];

            Graphics g1 = Graphics.FromImage(bitmap1);

            for (int alpha = 0; alpha < 256; alpha++)
            {
                g1.Clear(Color.FromArgb(alpha, 255, 255, 255));

                bytes[alpha] = new Byte[w * h * 3];

                BitmapData data1 = bitmap1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                Marshal.Copy(data1.Scan0, bytes[alpha], 0, bytes[alpha].Length);
                bitmap1.UnlockBits(data1);
            }

            bitmap2 = new Bitmap(w, h);
            g2 = Graphics.FromImage(bitmap2);
        }

        Bitmap bitmap1;
        Bitmap bitmap2;
        Graphics g2;

        Timer timer1 = new Timer();

        private void Draw(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImage(bitmap2, 0, 0);
        }

        int alpha = 1;
        int plus = 50;

        private void Draw_Animation(object sender, EventArgs e)
        {
            BitmapData data2 = bitmap2.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            unsafe
            {
                for (int i = 0; i < w * h * 3; i++)
                    ((byte*)data2.Scan0)[i] = this.bytes[alpha][i];
            }

            //Marshal.Copy(bytes[alpha], 0, data2.Scan0, bytes[alpha].Length);

            bitmap2.UnlockBits(data2);

            this.alpha += plus;
            if (alpha > 255)
            {
                alpha = 255;
                plus *= -1;
            }
            if (alpha < 0)
            {
                alpha = 0;
                plus *= -1;
            }

            this.Invalidate();
        }
    }
}
Posted
Updated 29-Jun-21 2:05am
v2

Marshal.Copy and Buffer.BlockCopy use the framework's kernel and c++ code to move the bytes around which is going to be faster than your higher level c# code.
   
Comments
Sergey Alexandrovich Kryukov 19-Jan-15 14:52pm
   
Well, you give some idea, but that's not all. This is, strictly speaking, is not because C++, but the methods of combining managed and unmanaged code, and involved overhead. Also, and I'm not sure the timing was performed correctly; certain things should be carried out of equation.

Please see Solution 2 where I explain it.

—SA
The question is not correctly posed. "Unsafe" cannot be faster or slower, because unsafe is not a statement which cause generation of some code taking any CPU time. It's merely the statement which allows you to do the pointer operations. So, everything depends on what you do with your pointer operations. The actual performance depends on many factors.

Take the use of Marshal.Copy. Its implementation can be optimized, for example, not because this is C++, but because it can use some preliminary created unmanaged code, somehow optimized. Remember that IL is based on JIT (http://en.wikipedia.org/wiki/Just-in-time_compilation[^]). When you use unsafe, you still use managed objects, which should be pinned (LockBits actually does that), and so one. It's hard to say how it translates into overall performance. I would not be much surprised if you manage to build some other code sample where your pointer arithmetic turns out faster than some other approach.

By the way, if you do your experiment with performance, it's important to exclude the time taken by JIT compilation. How? JIT normally works on per-method basis. So, before measuring timing, you need to make sure that every timed method was already called before at least once, with all the other methods it calls. Use System.Diagnostics.StopWatch for timing.

—SA
   
v2
As Sergey already mentions, it is not the keyword unsafe, but your code that's slower.

You are using a for loop where Marshal.Copy most probably uses something like the c++ std::memcpy under the hood.
std::memcpy takes advantage of block copy capabilities of you computers hardware. Which means that in the time your loop copies 1 byte, the hardware can copy a block of memory of for example 256 bytes.
   
Comments
Richard MacCutchan 29-Jun-21 8:18am
   
I think that after six years, OP has moved on.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900