使用 x86 汇编实现 C# 的快速内存拷贝(2)

void CopyImage()
{
  //start stopwatch
  Stopwatch sw = new Stopwatch();
  sw.Start();
 
  //copy-past data 10 times
  for (int i = 0; i < 10; i++)
  {
    System.Runtime.InteropServices.Marshal.Copy(bmpd.Scan0, buffer, 0, buffer.Length);
  }
 
  //stop stopwatch
  sw.Stop();
 
  //show measured time
  MessageBox.Show(sw.ElapsedTicks.ToString());
}

这就是标准快速拷贝方法。其实一点也不复杂,我们使用了知名的  System.Runtime.InteropServices.Marshal.Copy  方法。

以及又一个“中间方法(middle-method)”以用于快速拷贝逻辑:

void FastCopyImage()
{
  FastMemCopy.FastMemoryCopy(bmpd.Scan0, bmpd2.Scan0, buffer.Length);
}

现在,来实现FastMemCopy类。下面是类的声明以及我们将会在类中使用到的一些类型:

internal static class FastMemCopy
{
  [Flags]
  private enum AllocationTypes : uint
  {
    Commit = 0x1000,  Reserve = 0x2000,
    Reset = 0x80000,  LargePages = 0x20000000,
    Physical = 0x400000,  TopDown = 0x100000,
    WriteWatch = 0x200000
  }
 
  [Flags]
  private enum MemoryProtections : uint
  {
    Execute = 0x10,      ExecuteRead = 0x20,
    ExecuteReadWrite = 0x40,  ExecuteWriteCopy = 0x80,
    NoAccess = 0x01,    ReadOnly = 0x02,
    ReadWrite = 0x04,    WriteCopy = 0x08,
    GuartModifierflag = 0x100,  NoCacheModifierflag = 0x200,
    WriteCombineModifierflag = 0x400
  }
 
  [Flags]
  private enum FreeTypes : uint
  {
    Decommit = 0x4000,  Release = 0x8000
  }
 
  [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
  private unsafe delegate void FastMemCopyDelegate();
 
  private static class NativeMethods
  {
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr VirtualAlloc(
      IntPtr lpAddress,
      UIntPtr dwSize,
      AllocationTypes flAllocationType,
      MemoryProtections flProtect);
 
    [DllImport("kernel32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool VirtualFree(
      IntPtr lpAddress,
      uint dwSize,
      FreeTypes flFreeType);
  }

现在声明方法本身:

public static unsafe void FastMemoryCopy(IntPtr src, IntPtr dst, int nBytes)
{
  if (IntPtr.Size == 4)
        {
                //we are in 32 bit mode
 
                //allocate memory for our asm method
                IntPtr p = NativeMethods.VirtualAlloc(
                    IntPtr.Zero,
                    new UIntPtr((uint)x86_FastMemCopy_New.Length),
                    AllocationTypes.Commit | AllocationTypes.Reserve,
                    MemoryProtections.ExecuteReadWrite);
 
                try
                {
                    //copy our method bytes to allocated memory
                    Marshal.Copy(x86_FastMemCopy_New, 0, p, x86_FastMemCopy_New.Length);
 
                    //make a delegate to our method
                    FastMemCopyDelegate _fastmemcopy =
      (FastMemCopyDelegate)Marshal.GetDelegateForFunctionPointer(p,
        typeof(FastMemCopyDelegate));
 
                    //offset to the end of our method block
                    p += x86_FastMemCopy_New.Length;
 
                    //store length param
                    p -= 8;
                    Marshal.Copy(BitConverter.GetBytes((long)nBytes), 0, p, 4);
 
                    //store destination address param
                    p -= 8;
                    Marshal.Copy(BitConverter.GetBytes((long)dst), 0, p, 4);
 
                    //store source address param
                    p -= 8;
                    Marshal.Copy(BitConverter.GetBytes((long)src), 0, p, 4);
 
                    //Start stopwatch
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
 
                    //copy-past all data 10 times
                    for (int i = 0; i < 10; i++)
                        _fastmemcopy();
 
                    //stop stopwatch
                    sw.Stop();
 
                    //get message with measured time
                    System.Windows.Forms.MessageBox.Show(sw.ElapsedTicks.ToString());
                }
                catch (Exception ex)
                {
                    //if any exception
                    System.Windows.Forms.MessageBox.Show(ex.Message);
                }
                finally
                {
                    //free allocated memory
                    NativeMethods.VirtualFree(p, (uint)(x86_FastMemCopy_New.Length),
      FreeTypes.Release);
                    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                }
  }
  else if (IntPtr.Size == 8)
        {
                throw new ApplicationException("x64 is not supported yet!");
  }
}

汇编代码被表示成带注释的字节数组:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/45be6330e9b5e25282ad563da1cad68a.html