如何优化C for循环?
我的代码中的瓶颈部分存在性能问题。基本上它是一个简单的嵌套循环 分析该问题表明,该程序只需增加循环计数器(++)和测试终止(i/j<8)就可以花费大量时间 观察汇编输出,我发现两个计数器都没有得到寄存器,访问它们需要很多周期。使用“register”关键字并不能说服编译器将它们实际放入寄存器中。是否可以采取措施来优化计数器访问时间 这是程序集输出。C源代码只是一个带有i/j计数器的简单嵌套循环如何优化C for循环?,c,optimization,compiler-construction,C,Optimization,Compiler Construction,我的代码中的瓶颈部分存在性能问题。基本上它是一个简单的嵌套循环 分析该问题表明,该程序只需增加循环计数器(++)和测试终止(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);