Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何优化C for循环?_C_Optimization_Compiler Construction - Fatal编程技术网

如何优化C for循环?

如何优化C for循环?,c,optimization,compiler-construction,C,Optimization,Compiler Construction,我的代码中的瓶颈部分存在性能问题。基本上它是一个简单的嵌套循环 分析该问题表明,该程序只需增加循环计数器(++)和测试终止(i/j

我的代码中的瓶颈部分存在性能问题。基本上它是一个简单的嵌套循环

分析该问题表明,该程序只需增加循环计数器(++)和测试终止(i/j<8)就可以花费大量时间

观察汇编输出,我发现两个计数器都没有得到寄存器,访问它们需要很多周期。使用“register”关键字并不能说服编译器将它们实际放入寄存器中。是否可以采取措施来优化计数器访问时间

这是程序集输出。C源代码只是一个带有i/j计数器的简单嵌套循环

  2738  0.2479  2459  0.1707   :    1e6c:   jne    1dd1 <process_hooks+0x121>
  1041  0.0942  1120  0.0778   :    1e72:   addl   $0x1,0xffffffd4(%ebp)
  2130  0.1928  2102  0.1459   :    1e76:   cmpl   $0x8,0xffffffd4(%ebp)
  2654  0.2403  2337  0.1622   :    1e7a:   jne    1da0 <process_hooks+0xf0>
  809   0.0732   814  0.0565   :    1e80:   jmp    1ce2 <process_hooks+0x32>
2738 0.2479 2459 0.1707:1e6c:jne 1dd1
10410.0942 1120.0778:1e72:addl$0x1,0xffffffd4(%ebp)
2130 0.1928 2102 0.1459:1e76:cmpl$0x8,0xffffffd4(%ebp)
2654 0.2403 2337 0.1622:1e7a:jne 1da0
809 0.0732 814 0.0565:1e80:jmp 1ce2
根据要求,这里还有C代码。编译器是gcc btw:

for (byte_index=0; byte_index < MASK_SIZE / NBBY; byte_index++)
{
    if (check_byte(mask,byte_index))
    {
        for (bit_index=0; bit_index < NBBY; bit_index++)
        {
            condition_index = byte_index*NBBY + bit_index;
            if (check_bit(condition_mask,condition_index))
            {
                .
                .
                .
            }
        }
    }
}
for(字节索引=0;字节索引

谢谢

< P>当在循环计数器中获得性能瓶颈时,你应该考虑循环。


编辑:和往常一样,在优化时,确保进行基准测试并说服自己获得了所需的结果。

您可以尝试展开循环。编译器可能会为您这样做,但如果没有,并且您确实需要性能,请自己做。我假设您正在执行类似于每次迭代调用
函数(..,I,j,…)
的操作,因此只需将循环替换为:

function(.., 0, 0, ..)
...
function(.., 0, 7, ..)
function(.., 1, 0, ..)
...
function(.., 7, 7, ..)
有了更多的上下文(C源代码),可能会有更多有用的事情要做。坦率地说,如果两个堆栈分配计数器(许多现代处理器都有特殊的加速器硬件,可以像寄存器一样快速访问堆栈的顶部位)在非玩具程序中引起明显的问题,我会感到震惊。

表明“register关键字是一个有点过时的过程,因为在相当长的一段时间内,现代编译器中的优化器足够智能,能够检测何时将变量存储在寄存器上,这将是一个有利的过程,并且会在优化过程中这样做。例如,建议编译器在寄存器上存储一个变量只会使错误使用的速度变慢”

我猜这在很大程度上取决于您的编译器和优化级别。正如其他人所说,这可能是-funroll所有循环(gcc)的一个很好的候选者。

使用英特尔编译器时获得的最佳结果(速度方面)

您说得对,“register”关键字只是作为编译器的提示(就像inline一样)

如果你真的认为这个循环是一个主要的瓶颈,只需输入raw assembly就可以了。我知道它很难移植,但再说一次,通常这并不重要,如果它应该是可移植的……它只在一个特定的地方


您甚至可以使用原始C代码定义整个位以保持可移植性

您需要确保这是一个瓶颈,在现代处理器上,指令被分离,部分指令被无序执行,使用缓存和查找缓冲区,这完全可能不会再慢。

我希望不会这两个函数是内联的(check_bit和check_byte),因为它们比任何寄存器变量都慢得多


如果编译器没有将它们内联,请将它们自己内联到循环中。

如果编译器试图将计数器放入寄存器中,则必须为循环中的每个函数调用保存和还原寄存器(可能取决于这些函数的定义位置)。内联函数应该会大大加快速度(如果这真的是您的瓶颈)。

有两个可能的原因使它无法放入寄存器:

变量需要保存在内存中 如果您正在获取变量的地址或声明它为volatile,则它不会保存在寄存器中。看起来您没有这样做,但它可能发生在
部分

gcc在寄存器分配方面做得很差。 这是很有可能的。gcc似乎有一个糟糕的分配器(根据其开发人员的评论)。此外,寄存器分配是变化无常的,很难解释。您可能可以通过调整它来获得一些好处。如果您愿意,您可以将其设置为

GCC4.4有一个新的寄存器分配器,它应该更好,但也允许您选择分配算法。这将提供额外的东西来调整

您还可以尝试告诉gcc更努力地尝试,使用

最后,您还可以使用gcc的
--param
标志进行调整。它们公开了内部编译器设置,因此这一点可能不应该轻易开始。

for(bit_index=0;bit_index    for (bit_index=0; bit_index < NBBY; bit_index++)
    {
        condition_index = byte_index*NBBY + bit_index;
        if (check_bit(condition_mask,condition_index))
        {
            .
            .
            .
        }
    }
{ 条件索引=字节索引*NBBY+位索引; if(检查位(条件屏蔽、条件索引)) { . . . } } 也可能很容易

    condition_index = byte_index * NBBY;
    for (bit_index=0; bit_index < NBBY; bit_index++, condition_index++)
    {
        if (check_bit(condition_mask,condition_index))
        {
            .
            .
            .
        }
    }
条件索引=字节索引*NBBY;
对于(位索引=0;位索引
我喜欢将计算保持在正确的范围内。你在外循环中有这个的所有信息,但选择在内循环中进行。新循环稍微混乱一些,但这是可以避免的,现在它更复杂了
for (byte_index = 0; byte_index < MASK_SIZE / NBBY; )
{
    if (check_byte(mask,byte_index++))
    {
        condition_index = byte_index*NBBY;
        for (bit_index=0; bit_index < NBBY; )
        {
            if (check_bit(condition_mask,condition_index + bit_index++))
            {
                ...
            }
        }
    }
}
for (byte_index = 0; byte_index < MASK_SIZE / NBBY; byte_index++)
{
    if (check_byte(mask,byte_index))
    {
        const char masks[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
        for (mask_index=0; mask_index < sizeof(masks) / sizeof(masks[0]); mask_index++)
        {
            if (check_bit(masks[mask_index], byte_index))
            {
                ...
            }
        }
    }
}
//define the functions
void func0()
{
   printf("No Bits are on.");
}

void func1()
{
   printf("Bit 0 is on.");
}
.
.
.

//create the table
void  (*table[256])();
table[0] = &func0;
table[1] = &func1;
.
.
.

//the for loop
void  (*pointer_to_func)();
for...
{
   X = getByte();
   pointer_to_func = table[X]; //table shell contain 256 function pointers.
   pointer_to_func(); //call the function
}
for (condition_index = 0; condition_index < MASK_SIZE;)
{
    if (check_byte(mask, condition_index / NBBY))
    {
        for (bound = condition_index + NBBY; condition_index < bound; condition_index++)
        {
            if (check_bit(condition_mask, condition_index))
            {
                /* stuff */
            }
        }
    }
    else
    {
        condition_index += NBBY;
    }
}
for (n = 0, condition_index = 0; condition_index < MASK_SIZE;)
{
    if (check_byte(mask, condition_index / NBBY))
    {
        for (bound = condition_index + NBBY; condition_index < bound; condition_index++)
        {
            if (check_bit(condition_mask, condition_index))
            {
                condition_true[n++] = condition_index;
            }
        }
    }
    else
    {
        condition_index += NBBY;
    }
}

do {
    condition_index = condition_true[--n];
    /* Stuff */
} while (n > 0);