日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
使用x86匯編實現(xiàn)C#的快速內(nèi)存拷貝

介紹
 

大家好,我是Oleksandr Karpov,這個是我***次發(fā)表文章,希望大家喜歡。

創(chuàng)新互聯(lián)建站服務項目包括天臺網(wǎng)站建設、天臺網(wǎng)站制作、天臺網(wǎng)頁制作以及天臺網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網(wǎng)行業(yè)的解決方案,天臺網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到天臺省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!

在這我將為大家展示和介紹怎么樣在C#和.NET下使用匯編秒速拷貝數(shù)據(jù),在我是實例里面我用了一運用程序創(chuàng)建了一段視頻,里面包含圖片,視頻和聲音。

當然如果你也需要在C#使用匯編的情況,這方法給你提供一個快速簡單的解決途徑。

背景

理解本文的內(nèi)容, ***具備以下知識: 匯編語言, 內(nèi)存對齊, c#, windows 和 .net 高級技巧(advanced techniques).
 要提高數(shù)據(jù)復制(copy-past )的速度, 我們需要將內(nèi)存地址按 16 個字節(jié)對齊. 否則, 速度不會有明顯的改變. (我的例子大概快 1.02 倍 )
 
Pentium III+ (KNI/MMX2) 和 AMD Athlon (AMD EMMX) 這兩種處理器都支持本文代碼用到 SSE 指令集.

我用配置為: Pentium Dual-Core E5800 3.2GHz, 4GB 雙通道內(nèi)存的計算機做測試, 16 個字節(jié)內(nèi)存對齊的速度要比標準方式快 1.5 倍, 而非內(nèi)存對齊方式的速度幾乎沒有變化(1.02倍).

使用代碼

這是一個完整的演示測試,向你展示了性能測試以及如何使用。

FastMemCopy   類包含了用于快速內(nèi)存拷貝邏輯的所有內(nèi)容。

首先你需要創(chuàng)建一個默認的Windows Forms應用程序工程,在窗體上放兩個按鈕,一個PictureBox 控件,因為我們將用圖片來測試。

聲明幾個字段先:

 
 
  1. string bitmapPath;
  2. Bitmap bmp, bmp2;
  3. BitmapData bmpd, bmpd2;
  4. byte[] buffer = null;

現(xiàn)在創(chuàng)建兩個方法用來處理按鈕的點擊事件。

標準方法如下:

 
 
  1. private void btnStandard_Click(object sender, EventArgs e)
  2. {
  3.         using (OpenFileDialog ofd = new OpenFileDialog())
  4.         {
  5.             if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
  6.                 return;
  7.  
  8.             bitmapPath = ofd.FileName;
  9.         }
  10.  
  11.   //open a selected image and create an empty image with the same size
  12.         OpenImage();
  13.  
  14.   //unlock for read and write images
  15.         UnlockBitmap();
  16.  
  17.   //copy data from one image to another by standard method
  18.         CopyImage();
  19.  
  20.   //lock images to be able to see them
  21.         LockBitmap();
  22.  
  23.   //lets see what we have
  24.         pictureBox1.Image = bmp2;
  25. }

快速方法如下:

 
 
  1. private void btnFast_Click(object sender, EventArgs e)
  2. {
  3.   using (OpenFileDialog ofd = new OpenFileDialog())
  4.         {
  5.             if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
  6.                 return;
  7.             bitmapPath = ofd.FileName;
  8.         }
  9.  
  10.   //open a selected image and create an empty image with the same size
  11.         OpenImage();
  12.  
  13.   //unlock for read and write images
  14.         UnlockBitmap();
  15.  
  16.   //copy data from one image to another with our fast method
  17.         FastCopyImage();
  18.  
  19.   //lock images to be able to see them
  20.         LockBitmap();
  21.  
  22.   //lets see what we have
  23.         pictureBox1.Image = bmp2;
  24. }

好的,現(xiàn)在我們有按鈕并且也有了事件處理,下面來實現(xiàn)打開圖片、鎖定、解鎖它們的方法,以及標準拷貝方法:

打開一個圖片:

 
 
  1. void OpenImage()
  2. {
  3.   pictureBox1.Image = null;
  4.   buffer = null;
  5.   if (bmp != null)
  6.   {
  7.     bmp.Dispose();
  8.     bmp = null;
  9.   }
  10.   if (bmp2 != null)
  11.   {
  12.     bmp2.Dispose();
  13.     bmp2 = null;
  14.   }
  15.   GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
  16.  
  17.   bmp = (Bitmap)Bitmap.FromFile(bitmapPath);
  18.  
  19.   buffer = new byte[bmp.Width * 4 * bmp.Height];
  20.   bmp2 = new Bitmap(bmp.Width, bmp.Height, bmp.Width * 4, PixelFormat.Format32bppArgb,
  21.     Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0));
  22. }

鎖定和解鎖位圖:

 
 
  1. void UnlockBitmap()
  2. {
  3.   bmpd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, 
  4.     PixelFormat.Format32bppArgb);
  5.   bmpd2 = bmp2.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, 
  6.     PixelFormat.Format32bppArgb);
  7. }
  8.  
  9. void LockBitmap()
  10. {
  11.   bmp.UnlockBits(bmpd);
  12.   bmp2.UnlockBits(bmpd2);
  13. }

從一個圖片拷貝數(shù)據(jù)到另一個圖片,并且顯示測得的時間:

 
 
  1. void CopyImage()
  2. {
  3.   //start stopwatch
  4.   Stopwatch sw = new Stopwatch();
  5.   sw.Start();
  6.  
  7.   //copy-past data 10 times
  8.   for (int i = 0; i < 10; i++)
  9.   {
  10.     System.Runtime.InteropServices.Marshal.Copy(bmpd.Scan0, buffer, 0, buffer.Length);
  11.   }
  12.  
  13.   //stop stopwatch
  14.   sw.Stop();
  15.  
  16.   //show measured time
  17.   MessageBox.Show(sw.ElapsedTicks.ToString());
  18. }

這就是標準快速拷貝方法。其實一點也不復雜,我們使用了老牌的  System.Runtime.InteropServices.Marshal.Copy   方法。

以及又一個“中間方法(middle-method)”以用于快速拷貝邏輯:

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

現(xiàn)在,來實現(xiàn)FastMemCopy類。下面是類的聲明以及我們將會在類中使用到的一些類型:

 
 
  1. internal static class FastMemCopy
  2. {
  3.   [Flags]
  4.   private enum AllocationTypes : uint
  5.   {
  6.     Commit = 0x1000,  Reserve = 0x2000,
  7.     Reset = 0x80000,  LargePages = 0x20000000,
  8.     Physical = 0x400000,  TopDown = 0x100000,
  9.     WriteWatch = 0x200000
  10.   }
  11.  
  12.   [Flags]
  13.   private enum MemoryProtections : uint
  14.   {
  15.     Execute = 0x10,      ExecuteRead = 0x20,
  16.     ExecuteReadWrite = 0x40,  ExecuteWriteCopy = 0x80,
  17.     NoAccess = 0x01,    ReadOnly = 0x02,
  18.     ReadWrite = 0x04,    WriteCopy = 0x08,
  19.     GuartModifierflag = 0x100,  NoCacheModifierflag = 0x200,
  20.     WriteCombineModifierflag = 0x400
  21.   }
  22.  
  23.   [Flags]
  24.   private enum FreeTypes : uint
  25.   {
  26.     Decommit = 0x4000,  Release = 0x8000
  27.   }
  28.  
  29.   [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
  30.   private unsafe delegate void FastMemCopyDelegate();
  31.  
  32.   private static class NativeMethods
  33.   {
  34.     [DllImport("kernel32.dll", SetLastError = true)]
  35.     internal static extern IntPtr VirtualAlloc(
  36.       IntPtr lpAddress,
  37.       UIntPtr dwSize,
  38.       AllocationTypes flAllocationType,
  39.       MemoryProtections flProtect);
  40.  
  41.     [DllImport("kernel32")]
  42.     [return: MarshalAs(UnmanagedType.Bool)]
  43.     internal static extern bool VirtualFree(
  44.       IntPtr lpAddress,
  45.       uint dwSize,
  46.       FreeTypes flFreeType);
  47.   }

現(xiàn)在聲明方法本身:

 
 
  1. public static unsafe void FastMemoryCopy(IntPtr src, IntPtr dst, int nBytes)
  2. {
  3.   if (IntPtr.Size == 4)
  4.         {
  5.                 //we are in 32 bit mode
  6.  
  7.                 //allocate memory for our asm method
  8.                 IntPtr p = NativeMethods.VirtualAlloc(
  9.                     IntPtr.Zero,
  10.                     new UIntPtr((uint)x86_FastMemCopy_New.Length),
  11.                     AllocationTypes.Commit | AllocationTypes.Reserve,
  12.                     MemoryProtections.ExecuteReadWrite);
  13.  
  14.                 try
  15.                 {
  16.                     //copy our method bytes to allocated memory
  17.                     Marshal.Copy(x86_FastMemCopy_New, 0, p, x86_FastMemCopy_New.Length);
  18.  
  19.                     //make a delegate to our method
  20.                     FastMemCopyDelegate _fastmemcopy = 
  21.       (FastMemCopyDelegate)Marshal.GetDelegateForFunctionPointer(p, 
  22.         typeof(FastMemCopyDelegate));
  23.  
  24.                     //offset to the end of our method block
  25.                     p += x86_FastMemCopy_New.Length;
  26.  
  27.                     //store length param
  28.                     p -= 8;
  29.                     Marshal.Copy(BitConverter.GetBytes((long)nBytes), 0, p, 4);
  30.  
  31.                     //store destination address param
  32.                     p -= 8;
  33.                     Marshal.Copy(BitConverter.GetBytes((long)dst), 0, p, 4);
  34.  
  35.                     //store source address param
  36.                     p -= 8;
  37.                     Marshal.Copy(BitConverter.GetBytes((long)src), 0, p, 4);
  38.  
  39.                     //Start stopwatch
  40.                     Stopwatch sw = new Stopwatch();
  41.                     sw.Start();
  42.  
  43.                     //copy-past all data 10 times
  44.                     for (int i = 0; i < 10; i++)
  45.                         _fastmemcopy();
  46.  
  47.                     //stop stopwatch
  48.                     sw.Stop();
  49.  
  50.                     //get message with measured time
  51.                     System.Windows.Forms.MessageBox.Show(sw.ElapsedTicks.ToString());
  52.                 }
  53.                 catch (Exception ex)
  54.                 {
  55.                     //if any exception
  56.                     System.Windows.Forms.MessageBox.Show(ex.Message);
  57.                 }
  58.                 finally
  59.                 {
  60.                     //free allocated memory
  61.                     NativeMethods.VirtualFree(p, (uint)(x86_FastMemCopy_New.Length), 
  62.       FreeTypes.Release);
  63.                     GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
  64.                 }
  65.   }
  66.   else if (IntPtr.Size == 8)
  67.         {
  68.                 throw new ApplicationException("x64 is not supported yet!");
  69.   }
  70. }

匯編代碼被表示成帶注釋的字節(jié)數(shù)組:

 
 
  1. private static byte[] x86_FastMemCopy_New = new byte[]
  2. {
  3.   0x90, //nop do nothing
  4.   0x60, //pushad store flag register on stack
  5.   0x95, //xchg ebp, eax eax contains memory address of our method
  6.   0x8B, 0xB5, 0x***, 0x01, 0x00, 0x00, //mov esi,[ebp][0000001***] get source buffer address
  7.   0x89, 0xF0, //mov eax,esi
  8.   0x83, 0xE0, 0x0F, //and eax,00F will check if it is 16 byte aligned
  9.   0x8B, 0xBD, 0x62, 0x01, 0x00, 0x00, //mov edi,[ebp][000000162] get destination address
  10.   0x89, 0xFB, //mov ebx,edi
  11.   0x83, 0xE3, 0x0F, //and ebx,00F will check if it is 16 byte aligned
  12.   0x8B, 0x8D, 0x6A, 0x01, 0x00, 0x00, //mov ecx,[ebp][00000016A] get number of bytes to copy
  13.   0xC1, 0xE9, 0x07, //shr ecx,7 divide length by 128
  14.   0x85, 0xC9, //test ecx,ecx check if zero
  15.   0x0F, 0x84, 0x1C, 0x01, 0x00, 0x00, //jz 000000146 ↓ copy the rest
  16.   0x0F, 0x18, 0x06, //prefetchnta [esi] pre-fetch non-temporal source data for reading
  17.   0x85, 0xC0, //test eax,eax check if source address is 16 byte aligned
  18.   0x0F, 0x84, 0x8B, 0x00, 0x00, 0x00, //jz 0000000C0 ↓ go to copy if aligned
  19.   0x0F, 0x18, 0x86, 0x80, 0x02, 0x00, 0x00, //prefetchnta [esi][000000280] pre-fetch more source data
  20.   0x0F, 0x10, 0x06, //movups xmm0,[esi] copy 16 bytes of source data
  21.   0x0F, 0x10, 0x4E, 0x10, //movups xmm1,[esi][010] copy more 16 bytes
  22.   0x0F, 0x10, 0x56, 0x20, //movups xmm2,[esi][020] copy more
  23.   0x0F, 0x18, 0x86, 0xC0, 0x02, 0x00, 0x00, //prefetchnta [esi][0000002C0] pre-fetch more
  24.   0x0F, 0x10, 0x5E, 0x30, //movups xmm3,[esi][030]
  25.   0x0F, 0x10, 0x66, 0x40, //movups xmm4,[esi][040]
  26.   0x0F, 0x10, 0x6E, 0x50, //movups xmm5,[esi][050]
  27.   0x0F, 0x10, 0x76, 0x60, //movups xmm6,[esi][060]
  28.   0x0F, 0x10, 0x7E, 0x70, //movups xmm7,[esi][070] we've copied 128 bytes of source data
  29.   0x85, 0xDB, //test ebx,ebx check if destination address is 16 byte aligned
  30.   0x74, 0x21, //jz 000000087 ↓ go to past if aligned
  31.   0x0F, 0x11, 0x07, //movups [edi],xmm0 past first 16 bytes to non-aligned destination address
  32.   0x0F, 0x11, 0x4F, 0x10, //movups [edi][010],xmm1 past more
  33.   0x0F, 0x11, 0x57, 0x20, //movups [edi][020],xmm2
  34.   0x0F, 0x11, 0x5F, 0x30, //movups [edi][030],xmm3
  35.   0x0F, 0x11, 0x67, 0x40, //movups [edi][040],xmm4
  36.   0x0F, 0x11, 0x6F, 0x50, //movups [edi][050],xmm5
  37.   0x0F, 0x11, 0x77, 0x60, //movups [edi][060],xmm6
  38.   0x0F, 0x11, 0x7F, 0x70, //movups [edi][070],xmm7 we've pasted 128 bytes of source data
  39.   0xEB, 0x1F, //jmps 0000000A6 ↓ continue
  40.   0x0F, 0x2B, 0x07, //movntps [edi],xmm0 past first 16 bytes to aligned destination address
  41.   0x0F, 0x2B, 0x4F, 0x10, //movntps [edi][010],xmm1 past more
  42.   0x0F, 0x2B, 0x57, 0x20, //movntps [edi][020],xmm2
  43.   0x0F, 0x2B, 0x5F, 0x30, //movntps [edi][030],xmm3
  44.   0x0F, 0x2B, 0x67, 0x40, //movntps [edi][040],xmm4
  45.   0x0F, 0x2B, 0x6F, 0x50, //movntps [edi][050],xmm5
  46.   0x0F, 0x2B, 0x77, 0x60, //movntps [edi][060],xmm6
  47.   0x0F, 0x2B, 0x7F, 0x70, //movntps [edi][070],xmm7 we've pasted 128 bytes of source data
  48.   0x81, 0xC6, 0x80, 0x00, 0x00, 0x00, //add esi,000000080 increment source address by 128
  49.   0x81, 0xC7, 0x80, 0x00, 0x00, 0x00, //add edi,000000080 increment destination address by 128
  50.   0x83, 0xE9, 0x01, //sub ecx,1 decrement counter
  51.   0x0F, 0x85, 0x7A, 0xFF, 0xFF, 0xFF, //jnz 000000035 ↑ continue if not zero
  52.   0xE9, 0x86, 0x00, 0x00, 0x00, //jmp 000000146 ↓ go to copy the rest of data
  53.  
  54.   0x0F, 0x18, 0x86, 0x80, 0x02, 0x00, 0x00, //prefetchnta [esi][000000280] pre-fetch source data
  55.   0x0F, 0x28, 0x06, //movaps xmm0,[esi] copy 128 bytes from aligned source address
  56.   0x0F, 0x28, 0x4E, 0x10, //movaps xmm1,[esi][010] copy more
  57.   0x0F, 0x28, 0x56, 0x20, //movaps xmm2,[esi][020]
  58.   0x0F, 0x18, 0x86, 0xC0, 0x02, 0x00, 0x00, //prefetchnta [esi][0000002C0] pre-fetch more data
  59.   0x0F, 0x28, 0x5E, 0x30, //movaps xmm3,[esi][030]
  60.   0x0F, 0x28, 0x66, 0x40, //movaps xmm4,[esi][040]
  61.   0x0F, 0x28, 0x6E, 0x50, //movaps xmm5,[esi][050]
  62.   0x0F, 0x28, 0x76, 0x60, //movaps xmm6,[esi][060]
  63.   0x0F, 0x28, 0x7E, 0x70, //movaps xmm7,[esi][070] we've copied 128 bytes of source data
  64.   0x85, 0xDB, //test ebx,ebx check if destination address is 16 byte aligned
  65.   0x74, 0x21, //jz 000000112 ↓ go to past if aligned
  66.   0x0F, 0x11, 0x07, //movups [edi],xmm0 past 16 bytes to non-aligned destination address
  67.   0x0F, 0x11, 0x4F, 0x10, //movups [edi][010],xmm1 past more
  68.   0x0F, 0x11, 0x57, 0x20, //movups [edi][020],xmm2
  69.   0x0F, 0x11, 0x5F, 0x30, //movups [edi][030],xmm3
  70.   0x0F, 0x11, 0x67, 0x40, //movups [edi][040],xmm4
  71.   0x0F, 0x11, 0x6F, 0x50, //movups [edi][050],xmm5
  72.   0x0F, 0x11, 0x77, 0x60, //movups [edi][060],xmm6
  73.   0x0F, 0x11, 0x7F, 0x70, //movups [edi][070],xmm7 we've pasted 128 bytes of data
  74.   0xEB, 0x1F, //jmps 000000131 ↓ continue copy-past
  75.   0x0F, 0x2B, 0x07, //movntps [edi],xmm0 past 16 bytes to aligned destination address
  76.   0x0F, 0x2B, 0x4F, 0x10, //movntps [edi][010],xmm1 past more
  77.   0x0F, 0x2B, 0x57, 0x20, //movntps [edi][020],xmm2
  78.   0x0F, 0x2B, 0x5F, 0x30, //movntps [edi][030],xmm3
  79.   0x0F, 0x2B, 0x67, 0x40, //movntps [edi][040],xmm4
  80.   0x0F, 0x2B, 0x6F, 0x50, //movntps [edi][050],xmm5
  81.   0x0F, 0x2B, 0x77, 0x60, //movntps [edi][060],xmm6
  82.   0x0F, 0x2B, 0x7F, 0x70, //movntps [edi][070],xmm7 we've pasted 128 bytes of data
  83.   0x81, 0xC6, 0x80, 0x00, 0x00, 0x00, //add esi,000000080 increment source address by 128
  84.   0x81, 0xC7, 0x80, 0x00, 0x00, 0x00, //add edi,000000080 increment destination address by 128
  85.   0x83, 0xE9, 0x01, //sub ecx,1 decrement counter
  86.   0x0F, 0x85, 0x7A, 0xFF, 0xFF, 0xFF, //jnz 0000000C0 ↑ continue copy-past if non-zero
  87.   0x8B, 0x8D, 0x6A, 0x01, 0x00, 0x00, //mov ecx,[ebp][00000016A] get number of bytes to copy
  88.   0x83, 0xE1, 0x7F, //and ecx,07F get rest number of bytes
  89.   0x85, 0xC9, //test ecx,ecx check if there are bytes
  90.   0x74, 0x02, //jz 000000155 ↓ exit if there are no more bytes
  91.   0xF3, 0xA4, //rep movsb copy rest of bytes
  92.   0x0F, 0xAE, 0xF8, //sfence performs a serializing operation on all store-to-memory instructions
  93.   0x61, //popad restore flag register
  94.   0xC3, //retn return from our method to C#
  95.    
  96.   0x00, 0x00, 0x00, 0x00, //source buffer address
  97.   0x00, 0x00, 0x00, 0x00,
  98.  
  99.   0x00, 0x00, 0x00, 0x00, //destination buffer address
  100.   0x00, 0x00, 0x00, 0x00,
  101.  
  102.   0x00, 0x00, 0x00, 0x00, //number of bytes to copy-past
  103.   0x00, 0x00, 0x00, 0x00
  104. };

我們將會通過前面創(chuàng)建的托管來調(diào)用匯編方法。

該方法目前工作在32位模式下,將來我會實現(xiàn)64位模式。

誰感興趣的話可以添加到源代碼中(文章中幾乎包含了所有的代碼)

興趣點

在實現(xiàn)及測試該方法期間,我發(fā)現(xiàn)prefetchnta命令描述的不是很清楚,甚至是Intel的說明書也是一樣。所以我嘗試自己以及通過google來弄明白[[125062]]。注意movntps和movaps說明,它們只在16字節(jié)內(nèi)存地址對齊時工作。

英文原文:C# - Fast memory copy method with x86 assembly usage

譯文出自:http://www.oschina.net/translate/csharp-fast-memory-copy-method-with-x-assembly-usa


分享文章:使用x86匯編實現(xiàn)C#的快速內(nèi)存拷貝
轉載來于:http://www.dlmjj.cn/article/cdogcie.html