optimizeMe (const char* string0, const char* string1)
{
int i0;
int i1 = strlen(string1) - 1;
int count = 0;
for (i0 = 0; i0 < strlen(string0); i0++)
{
if (toupper(string0[i0]) == toupper(string1[i1]))
count++;
count++;
if ((i0%32)==0)
i1--;
}
return(count / 8);
}
我知道我可以通过使用寄存器gcc -o2
,降低强度i0%32=0x10000
和通用表达式count/8 = count >> 3
等来优化此代码;
但是,如何通过代码移动来优化它们?专门用于if
语句和il--
。
任何提示表示赞赏!
答案 0 :(得分:0)
正如伦丁在评论中指出的那样,这些都是过早的优化。它们为时过早,因为您显然只是在猜测,而没有使用探查器在具有实际瓶颈的真实程序上测试您的理论。
它们也是 micro 的优化,并且自80年代以来,由于在技术上的重大突破,我们实际上并不需要在C中进行 micro 的优化。例如,我们要做令人惊奇的事情,例如实时模拟三维领域。
gcc
已支持您可能感兴趣的各种功能,例如死代码消除,代码提升(在某些情况下甚至进入编译时)和配置文件引导的优化。我认为我们理所当然我们拥有一个编译器,它可以通过代码的寂寞来静态推断出代码无法访问的事实;对于机器而言,这是相当复杂的优化。
通过在测试时进行概要分析,然后重新编译,将探查器数据反馈到编译器中,编译器获得有关如何重新排列分支以更好地进行预测的信息。这是配置文件引导的优化,并且是半自动化的。我不知道《德军总部3D》的作者会为这种技术做些什么...
说到探查器,如果我建议您在一些现实的用例(即具有活跃开发和庞大社区的实际程序)中对它们进行测试:
使用
register
力量降低
i%32=0x10000
count/8 = count >> 3
最后的优化isn't even correct for you(请参阅练习5),顺便说一下,这可能是时候提一下我们套件中的其他调试工具了。我强烈建议您检出ASan(和其他UBSans),这样可能会节省您调试时间小时。
最好使用size_t
,因为that's what strlen
returns首先,size_t
可以更方便地与strlen
一起使用,而且速度可能也更快(由于事实size_t
没有符号位,因此在编写for (size_t x = 0; x < y; x++)
)之类的东西时没有潜在的符号处理开销……
...,或者,如果您想向编译器提供特定于体系结构的提示(可能没有配置文件引导的优化,或者您不需要手动进行此操作),也可以使用{{ 3}}或其他并非真正适合该任务的东西,但仍比int
更合适。
我收集到,您必须从某个地方获取输入,否则您的程序是“纯净的”,从(功能上)意义上讲,它没有副作用,根本不会改变用户与系统交互的方式(在那方面)在这种情况下,您的编译器甚至可能会将所有逻辑都提升到编译时评估中)...您是否考虑过调整您所使用的任何文件和/或流(即stdin
和stdout
)的缓冲区大小重新使用?您应该能够使用uint_fast32_t
来执行此操作...如果一次打开许多流,则可能希望尝试选择较小的流缓冲区大小,以将所有内容保留在缓存中。我喜欢从1
的缓冲区大小开始,然后从那里继续前进,这样一来,您将准确地看到系统瓶颈在哪里...如果您要展开循环(gcc
会很高兴地自动进行(如果有好处的话 ))...
如果您使用的是真正原始的编译器(虽然分析器实际上可能会引导您直接进行最重要的优化,但您没有用,但优化您作为开发人员的时间) ,您也许可以建议编译器为这些行发出非分支代码:
// consider `count += (toupper((unsigned char) string[i0]) == toupper((unsigned char) string1[i1]));`?
if (toupper(string0[i0]) == toupper(string1[i1]))
count++;
强制进行强制转换是防止setvbuf
的必要...您绝对需要确保传递给<ctype.h>
函数的唯一值是unsigned char
值或{ {1}}。
EOF