【译】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

相关文章
相关标签/搜索