优化c函数以删除比较

优化c函数以删除比较,c,performance,optimization,C,Performance,Optimization,我一直在分析我们的应用程序,并发现了一些明显的问题,内存分配器被调用了很多次,并且占用了大量的时间(几%)。去年,我使内存分配器快了很多倍,但我仍然认为我可以加快一些。作为优化的一部分,我想加速量化分配大小的代码部分 内存分配器保留可用内存块的列表。有一个832个列表的数组。0..128k范围内的每个分配大小都有一个列表。所有来自0..128k的分配请求都被转换为832个量子中的一个(量子是正确的词吗?)832是任意的,结果是我提出了下面的方案。我平衡了不浪费内存和大量重用的愿望。此外,我希望使

我一直在分析我们的应用程序,并发现了一些明显的问题,内存分配器被调用了很多次,并且占用了大量的时间(几%)。去年,我使内存分配器快了很多倍,但我仍然认为我可以加快一些。作为优化的一部分,我想加速量化分配大小的代码部分

内存分配器保留可用内存块的列表。有一个832个列表的数组。0..128k范围内的每个分配大小都有一个列表。所有来自0..128k的分配请求都被转换为832个量子中的一个(量子是正确的词吗?)832是任意的,结果是我提出了下面的方案。我平衡了不浪费内存和大量重用的愿望。此外,我希望使用尽可能少的位来存储分配的大小。在我们的应用程序中,对小尺寸的要求远高于对大尺寸的要求,即对小尺寸的重用更高。所有内容都与8字节对齐,因此最小的量子是8。我选择将256字节以下的所有分配量化为8字节,以避免浪费超过对齐要求的ram。另外,为了节省空间,当内存被添加到空闲内存列表中时,我使用分配内存的前8个字节作为下一个指针,因此我也不能低于8个字节。从2..8k开始,请求量为32字节。从8..32k到128字节。从32..128k到512字节。随着请求大小的增加,您可以使用更大的量子,并且仍然可以减少浪费的内存的%。因为我只有832个大小,所以重用率很高,即使对于更大/更稀有的分配也是如此

下面是量化分配请求的函数。iRecycle是列表数组的索引。从0到831

void GetAlignedSize(QWORD cb, QWORD& cbPack8, WORD& iRecycle) {
  // we assume cb is small, so the first 'if' will be hit the most.
  if (cb < 0x000800 - 0x0007) {        //  0k..2k   =   8 byte chunks
    cb += 0x0007; cbPack8 = cb & (~0x0007); // pad to 8
    iRecycle = 000 + WORD(cb >>  3);  
  } else if (cb < 0x002000 - 0x001f) { //  2k..8k   =  32 byte chunks
    cb += 0x001f; cbPack8 = cb & (~0x001f); // pad to 32
    iRecycle = 192 + WORD(cb >>  5);  
  } else if (cb < 0x008000 - 0x007f) { //  8k..32k  = 128 byte chunks
    cb += 0x007f; cbPack8 = cb & (~0x007f); // pad to 128
    iRecycle = 384 + WORD(cb >>  7);  
  } else if (cb < 0x020000 - 0x01ff) { // 32k..128k = 512 byte chunks 
    cb += 0x01ff; cbPack8 = cb & (~0x01ff); // pad to 512
    iRecycle = 576 + WORD(cb >>  9);  
  } else { 
    cbPack8 = Pack8(cb);
    iRecycle = 0;
  }
}
void GetAlignedSize(QWORD cb、QWORD和cbPack8、WORD和iRecycle){
//我们假设cb很小,所以第一个“如果”的命中率最高。
如果(cb<0x000800-0x0007){//0k..2k=8字节块
cb+=0x0007;cbPack8=cb&(~0x0007);//填充到8
iRecycle=000+字(cb>>3);
}else如果(cb<0x002000-0x001f){//2k..8k=32字节块
cb+=0x001f;cbPack8=cb&(~0x001f);//填充到32
iRecycle=192+字(cb>>5);
}else如果(cb<0x008000-0x007f){//8k..32k=128字节块
cb+=0x007f;cbPack8=cb&(~0x007f);//填充到128
iRecycle=384+字(cb>>7);
}else如果(cb<0x020000-0x01ff){//32k..128k=512字节块
cb+=0x01ff;cbPack8=cb&(~0x01ff);//填充到512
iRecycle=576+字(cb>>9);
}否则{
cbPack8=Pack8(cb);
i循环=0;
}
}
问题来了!我怎样才能做类似的事情,只有位操纵。我想去掉compare语句,因为我认为它会破坏cpu流水线。只要量化随大小而增加,并且128k以下大小的#很小,任何方案都是可行的。我希望这将消除最后一种情况,并且iRecycle将无限制地增加,因此我们可以将iRecycle更改为不同大小的整数


谢谢你的帮助

最明显的做法是使用表格。我怀疑这样的计划会更快,但好奇的是

…因此,为了创建基线,我调整了您的函数(用C呈现):

设置循环是:

  srand(314159) ;
  for (int i = 0 ; i < trial_count ; ++i)
    {
      int r ;
      size_t mx, mn ;

      r = rand() % 1000 ;
      if      (r < 800)
        {
          mn = 1 ;
          mx = 0x00800 ;
        }
      else if (r < 950)
        {
          mn = 0x00801 ;
          mx = 0x02000 ;
        }
      else if (r < 990)
        {
          mn = 0x02001 ;
          mx = 0x08000 ;
        }
      else if (r < 999)
        {
          mn = 0x08001 ;
          mx = 0x20000 ;
        }
      else
        {
          mn = 0x20001 ;
          mx = 0x80000 ;
        } ;

      test_values[i] = (rand() % (mx - mn + 1)) + mn ;
    } ;
总的来说(阅读并叹气)快了8%:-(


<>我很无聊。< /P>第一次的情况下,作为所有调用的百分比,多少次出现?这看起来是C++,而不是C,只是引用引用。你使用什么编译器和优化标志?最近的4.9次尝试(使用<代码> GCC-4.9- Munt=本机FLTO -O3 < /代码>编译和链接)?249的cb命中第一个if。250-256的cb命中第二个if,但仍量化为256。将第一个if重写为if(cb<0x800)对所有其他IFS也一样。边际改进,但更容易阅读。OOP抱歉。MSVC编译器有完全的优化。它是C++,但是C是好的。@ AIR:我最初把这些行每一行都排成一行,这样所有的东西都排好了,你可以看到应用的位模式。谢谢你的想法。哇,我没有想到T。可以。我可以将表定位在与代码相同的段中,因此我不需要额外的TLB命中。如果表非常小,它可能会在整个执行过程中保留在二级缓存中,因为它的命中率很高。这可能是表查找的一个非常好的候选。我们不必完全匹配原始函数。我认为我们可以表中包含32个条目,并使用msb作为索引。msb只有一条指令。这将消除<0x20000 cmp。稍后代码中会进行比较,以查找索引为零的索引。我可以将其更改为index>max recycle list。嗯,

static uint
get_aligned_size_1(size_t size, size_t* rsize)
{
  static const uint tb[0x40] =
  {
    /* 0x00 */  (0x007 << 16) + ((256 - 64) * 0)  + 3,

    /* 0x01 */  (0x01F << 16) + ((256 - 64) * 1)  + 5,
    /* 0x02 */  (0x01F << 16) + ((256 - 64) * 1)  + 5,
    /* 0x03 */  (0x01F << 16) + ((256 - 64) * 1)  + 5,

    /* 0x04 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x05 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x06 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x07 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x08 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x09 */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0A */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0B */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0C */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0D */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0E */  (0x07F << 16) + ((256 - 64) * 2)  + 7,
    /* 0x0F */  (0x07F << 16) + ((256 - 64) * 2)  + 7,

    /* 0x10 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x11 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x12 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x13 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x14 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x15 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x16 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x17 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x18 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x19 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1A */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1B */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1C */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1D */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1E */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x1F */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,

    /* 0x20 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x21 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x22 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x23 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x24 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x25 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x26 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x27 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x28 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x29 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2A */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2B */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2C */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2D */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2E */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x2F */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,

    /* 0x30 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x31 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x32 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x33 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x34 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x35 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x36 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x37 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x38 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x39 */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3A */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3B */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3C */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3D */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3E */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
    /* 0x3F */  (0x1FF << 16) + ((256 - 64) * 3)  + 9,
  } ;

  size_t sx = size - 1 ;

  if (size <= 0x20000)
    {
      uint tx ;

      tx = tb[sx >> 11] ;

      *rsize = (sx | (tx >> 16)) + 1 ;
      return (sx >> (tx & 0xF)) + (tx & 0xFFF0) ;
    } ;

  *rsize = 0 ;
  return 64 + ((256 - 64) * 4) ;
} ;
Setup:     15.610 secs: user  15.580 system   0.000 -- 500 million
Branches:   1.910 secs: user   1.910 system   0.000
Table 1:    1.840 secs: user   1.830 system   0.000
  srand(314159) ;
  for (int i = 0 ; i < trial_count ; ++i)
    {
      int r ;
      size_t mx, mn ;

      r = rand() % 1000 ;
      if      (r < 800)
        {
          mn = 1 ;
          mx = 0x00800 ;
        }
      else if (r < 950)
        {
          mn = 0x00801 ;
          mx = 0x02000 ;
        }
      else if (r < 990)
        {
          mn = 0x02001 ;
          mx = 0x08000 ;
        }
      else if (r < 999)
        {
          mn = 0x08001 ;
          mx = 0x20000 ;
        }
      else
        {
          mn = 0x20001 ;
          mx = 0x80000 ;
        } ;

      test_values[i] = (rand() % (mx - mn + 1)) + mn ;
    } ;
static uint
get_aligned_size_5(size_t size, size_t* rsize)
{
  static const uint8_t ts[0x40] =
  {
    /*                0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
    /* 0x00       */  3,
    /* 0x01..0x03 */     5, 5, 5,
    /* 0x04..0x0F */              7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    /* 0x10..0x1F */  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
    /* 0x20..0x2F */  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
    /* 0x30..0x3F */  9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
  } ;

  static const uint tb[16] =
  {
    /*  0 */    0,
    /*  1 */    0,
    /*  2 */    0,
    /*  3 */    ((256 - 64) / 2) * (3 - 3),
    /*  4 */    0,
    /*  5 */    ((256 - 64) / 2) * (5 - 3),
    /*  6 */    0,
    /*  7 */    ((256 - 64) / 2) * (7 - 3),
    /*  8 */    0,
    /*  9 */    ((256 - 64) / 2) * (9 - 3),
    /* 10 */    0,
    /* 11 */    0,
    /* 12 */    0,
    /* 13 */    0,
    /* 14 */    0,
    /* 15 */    0,
  } ;

  size_t sx = size - 1 ;

  if (size <= 0x20000)
    {
      uint8_t  s ;

      s = ts[sx >> 11] ;
      *rsize = (sx | (((size_t)1 << s) - 1)) + 1 ;
      return (sx >> s) + tb[s] ;
    } ;

  *rsize = 0 ;
  return 64 + ((256 - 64) * 4) ;
} ;
Setup:     15.610 secs: user  15.580 system   0.000 -- 500 million
Branches:   1.910 secs: user   1.910 system   0.000
Table 1:    1.840 secs: user   1.830 system   0.000
Table 5:    1.750 secs: user   1.750 system   0.000