有时候为了加快大量数据的存取操作,我优化了重要路径上的算法,用尽了精简代码的技巧,还采用处理指令矢量化的技能,为程序定制了一个内存管理器以增加程序的缓冲友好性(cache friendly),一般情况下是可以达到最终目的了,可在图像处理相关的代码中,竟然发现最大优化机会在地址访问上,比如本人曾经见过这样的source code:
  typedef unsigned Pixel32;
  struct Pixel24 { u8 r, g, b; };

  Pixel24* pRaw = new Pixel24[width*height];
  Pixel32* pSrcImg = loadFromFile("tangent.bmp");
  fillPort(pRaw, dstRt, pSrcImg, srcRt);   // 这个函数的内部实现对于32bit pixel -> 24bit pixel比较麻烦哦

我知道,典型的IA32系的处理器的寻址操作在机器字的n倍处最快的。
C++中:
  int a;
  Obj x;
的代码产生的访问对象的地址由编译器完成了!而且绝对保证以最快地方式访问;
 而 Obj* x;
      Pixel24* pRaw = new Pixel24[sizeof(Pixel24)*width*height];
      Pixel32* pSrcImg = ....
的pRaw, pSrcImg就随运行时而定,不一定在“机器字的n倍处”,而且其一部分数据在“机器字的n倍处”。

可想而知,32bit的像素在memory上很容得以地址对齐,但是也可能其首地址没有在机器字的n倍处,可24bit就更麻烦了。


所以我的策略是:动态分配时,多分配一个机器字的空间,然后想个办法让Pointer定在这个分配的线性空间内的首个“机器字的n倍处”,之后的对象访问对齐问题靠padding完成(不过,这一步只有在真的需要时才作,因为会有大量空间浪费!)。


这里给出了me的对齐code:

  template <typename Pointer, int Align =4>
  Pointer alignAddress(void* raw)
  { // 把raw对齐为机器字的整数倍,Align为机器字的字节数.(需要在raw处多分配align个字节)
    // Align默认为4,即32bit机的地址对齐
    Pointer p = reinterpret_cast<Pointer>(
      (reinterpret_cast<uintptr_t>(raw) + Align-1) & ~(Align-1) );   // 这里有点技巧
    return p;
  }

就这么点。

可以这样使用:
      #define ALIGN_SET 4
      Pixel24* pT = new unsigned char[sizeof(Pixel24)*width*height + ALIGN_SET];
      Pixel24* pRaw = alignAddress<Pixel24*, ALIGN_SET>(pT);
      // pRaw就是所要的地址,需要时对Pixel24开启编译器padding选项

      有了这样的保证,前面的fillPort的优化工作就更容易了!