【譯】AS3利用CPU緩存

利用CPU緩存

 

計算機有隨機存取存儲器RAM(譯註:即咱們常說的內存),但有更快形式的存儲器。若是你但願你的應用程序的快速運行,你須要知道這些其餘的存儲器。今天的文章中討論了它們,並給出了兩個AS3例子,即便有這樣的高級語言,你仍然能夠利用它們。

RAM的確很快,但只是與硬盤,固態硬盤,光盤,互聯網等等與比較時。RAMCPU內置的高速緩存相比,它並不快。你可能已經據說過他們,CPU高速緩存的級別分別稱爲:L1L2L3緩存

CPU高速緩存用來存儲小塊的RAM內容。當RAM被請求時,能夠使用更快的高速緩存,而不是...但只有當所請求的RAM是在高速緩存中的。這就是所謂的高速緩存「命中」。若是高速緩存「miss」,CPU須要從較慢的RAM來獲取。app

CPU的高速緩存策略各不相同,但RAM連續塊一般存儲在緩存中(譯註:由於程序運行時對內存的訪問呈現局部性(Locality)特徵。這種局部性既包括空間局部性(Spatial Locality),也包括時間局部性(Temporal Locality)。有效利用這種局部性,緩存能夠達到極高的命中率。不清楚的能夠回去補下課)。這意味着,若是你的應用程序的工做在連續的內存塊(如一個Vector)上而且大小不超太高速緩存大小限制,那麼CPU高速緩存將被命中,而不是從RAM中讀取,將收穫一個大的性能取勝。dom

用一個有點作做的例子來證實這一點,訪問一個大Vector中全部的元素模擬RAM。分別順序訪問,隨機訪問它們。爲了消除Math.random調用的影響,經過2Vector來存儲訪問元素的索引值。在隨機訪問的狀況下,Vector中存的索引值是隨機的,這樣元素將被隨機讀取。下面是10個元素的向量的例子,兩個索引值Vector可能以下所示:oop

/ /順序訪問(索引Vector中存儲的index值)性能

0 1 2 3 4 5 6 7 8 9測試

/ /隨機訪問(索引Vector中存儲的index值)ui

2 3 9 1 4 0 6 8 5 7spa

測試運行的環境:debug

Release version of Flash Player 12.0.0.41code

2.3 Ghz Intel Core i7-3615QM (256 KB L2 per core, 6 MB L3 cache)

Mac OS X 10.9.1

Google Chrome 32.0.1700.77

ASC 2.0.0 build 354071 (-debug=false -verbose-stacktraces=false -inline -optimize=true)

測試獲得的結以下:

訪問方式

耗時

順序

27

隨機

169

 

clip_image002[4]

由此咱們能夠看到使用了CPU緩存的順序訪問,比沒有使用CPU緩存的隨機訪問性能高6+倍。訪問內存的順序真的很重要!

誠然上面的例子有點作做,但下面的例子是處理實際問題:遍歷BitmapData的像素。須要一個循環來遍歷行(Y),一個循環來遍歷列(X)。哪一個做爲外循環,哪一個做爲內循環?

實際上,BitmapData是「逐行」存儲的。下面是3x2 BitmapData

(0,0) (1,0) (2,0) (0,1) (1,1) (1,2)

若是外循環是遍歷列(X),訪問這些內存的地址以下:

0 4 8 1 5 9 2 6 10 3 7 11

可是若是外循環是遍歷行(Y),訪問順序以下:

0 1 2 3 4 5 6 7 8 9 10 11

正如咱們上面所瞭解到,順序訪問能夠利用CPU緩存。彷佛只是跳序了一點點,可是當BitmapData實例很大的時候問題開始真正出現。若是BitmapData2048×2,前四個內存訪問將是0204712048

下面的例子比較了2048×2048BitmapData這兩種循環策略,測試環境與上面的相同:

BITMAPDATA外循環

耗時

89

348

 

clip_image004[4]

這裏的性能優點不像上面訪問Vector那麼大,但遍歷相同的像素時它仍然是高達4倍的優點。若是BitmapData是更大的,優點只會更大。這在CPU的緩存比個人測試環境中少的狀況更明顯。

下面是測試應用程序的源代碼:

Code

package
{
      import flash.display.BitmapData;
      import flash.display.Sprite;
      import flash.display.StageAlign;
      import flash.display.StageScaleMode;
      import flash.text.TextField;
      import flash.text.TextFieldAutoSize;
      import flash.utils.getTimer;
 
      public class CacheTest extends Sprite
      {
            private var logger:TextField = new TextField();
            private function row(...cols): void
            {
                  logger.appendText(cols.join(",")+"\n");
            }
 
            public function CacheTest()
            {
                  stage.scaleMode = StageScaleMode.NO_SCALE;
                  stage.align = StageAlign.TOP_LEFT;
 
                  logger.autoSize = TextFieldAutoSize.LEFT;
                  addChild(logger);
 
                  testVector();
                  row();
                  testBitmapData();
            }
 
            private function testVector(): void
            {
                  const SIZE:int = 10000000;
                  var beforeTime:int;
                  var afterTime:int;
                  var i:int;
                  var sum:int;
 
                  // Build vectors of indices
                  var inOrder:Vector.<int> = new Vector.<int>(SIZE);
                  for (i = 0; i < SIZE; ++i)
                  {
                        inOrder[i] = i;
                  }
                  var randomOrder:Vector.<int> = inOrder.slice();
                  shuffle(randomOrder);
 
                  row("Vector Access", "Time");
 
                  sum = 0;
                  beforeTime = getTimer();
                  for (i = 0; i < SIZE; ++i)
                  {
                        sum += inOrder[inOrder[i]];
                  }
                  afterTime = getTimer();
                  row("Sequential", (afterTime-beforeTime));
 
                  sum = 0;
                  beforeTime = getTimer();
                  for (i = 0; i < SIZE; ++i)
                  {
                        sum += randomOrder[randomOrder[i]];
                  }
                  afterTime = getTimer();
                  row("Random", (afterTime-beforeTime));
            }
 
            private function testBitmapData(): void
            {
                  var SIZE:int = 2048;
                  var bmd:BitmapData = new BitmapData(SIZE, SIZE, true, 0xff123456);
                  var curRow:int;
                  var curCol:int;
                  var sum:int;
                  var beforeTime:int;
                  var afterTime:int;
 
                  row("BitmapData Outer Loop", "Time");
 
                  sum = 0;
                  beforeTime = getTimer();
                  for (curRow = 0; curRow < SIZE; ++curRow)
                  {
                        for (curCol = 0; curCol < SIZE; ++curCol)
                        {
                               sum += bmd.getPixel32(curCol, curRow);
                        }
                  }
                  afterTime = getTimer();
                  row("Row", (afterTime-beforeTime));
 
                  sum = 0;
                  beforeTime = getTimer();
                  for (curCol = 0; curCol < SIZE; ++curCol)
                  {
                        for (curRow = 0; curRow < SIZE; ++curRow)
                        {
                               sum += bmd.getPixel32(curCol, curRow);
                        }
                  }
                  afterTime = getTimer();
                  row("Col", (afterTime-beforeTime));
            }
 
            private function shuffle(vec:Vector.<int>): void
            {
                  var len:uint = vec.length;
                  while (len)
                  {
                        var index:uint = Math.floor(Math.random() * len);
                        len--;
 
                        var temp:int = vec[len];
                        vec[len] = vec[index];
                        vec[index] = temp;
                  }
            }
      }
}

 

 

運行測試程序http://files.jacksondunstan.com/articles/2491/CacheTest.swf)。

原文連接:http://jacksondunstan.com/articles/2491

相關文章
相關標籤/搜索