修改我的C代码(最初是为Windows编写并在VS 2008下编译)后,我在Linux上运行它。令我惊讶的是,它现在至少比Windows版本慢10倍。
使用Profiler工具我发现以下函数占用了应用程序花费的大部分时间:
/* advance by n bits */
void Flush_Buffer(N)
int N;
{
int Incnt;
ld->Bfr <<= N;
Incnt = ld->Incnt -= N;
if (Incnt <= 24)
{
if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4))
{
do
{
if (ld->Rdptr >= ld->Rdmax)
Next_Packet();
ld->Bfr |= Get_Byte() << (24 - Incnt);
Incnt += 8;
}
while (Incnt <= 24);
}
else if (ld->Rdptr < ld->Rdbfr+2044)
{
do
{
ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
Incnt += 8;
}
while (Incnt <= 24);
}
else
{
do
{
if (ld->Rdptr >= ld->Rdbfr+2048)
Fill_Buffer();
ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
Incnt += 8;
}
while (Incnt <= 24);
}
ld->Incnt = Incnt;
}
}
此功能在Windows上花费的时间可以忽略不计。在Linux上它需要接近14秒。我在这里犯了什么错?
此处没有系统调用,因此此代码段应独立于OS特定的调用,因此应在相同的时间运行。
(我的猜测:这个函数被多次调用,所以分析器也可能累积所有调用的时间。在这种情况下,我认为其中一个问题可能是函数没有得到它的输入与windows案例相比,参数很快。)
我在这里犯了什么错?有什么猜测?
Rgrds,
H
答案 0 :(得分:1)
这更像是一个注释,而不是一个答案,但它并不完全符合评论,所以我希望你不要反对我。
术语“剖析”有几个相关但不同的含义。在抽象上下文中,它意味着“测量”您的程序,通常是针对某些运行时数据。但是,这与简单地“计时”你的程序不同。时间是一种分析形式,但还有很多其他形式。
例如,假设您不确定某些数据结构应该是std::set
(树)还是std::unordered_set
(哈希表)。没有通用答案,因为它取决于您使用它的内容以及您正在处理的数据。在您指定要使用的实际数据之前,完全有可能无法知道正确的答案。在这种情况下,“配置文件和决定”意味着您制作程序的两个版本,根据实际数据运行它们,并测量运行时。更快的可能就是你想要的那个。
另一方面,GCC有一个名为“profiler”的工具,它的用途非常不同。它是一个执行路径分析器,如果你愿意,它会告诉你程序在大部分时间内花费的位置(即在哪个函数中)。如果你有一个包含大量子程序的复杂算法,你可能不知道哪些是重要的,并且这实际上可能取决于你的实际输入。在这种情况下,分析器可以帮助您确定哪些函数被称为最多给定您的输入数据,并且您可以将优化工作集中在这些函数上。现在“优化之前的配置文件”意味着您需要在开始工作之前确定优先级。
那就是说,为了比较你的想法,你不能使用GCC分析器。而是在两个平台上进行编译,启用所有优化并在释放条件下,然后在同一组输入数据上测量运行时。
答案 1 :(得分:0)
您可以尝试使用计数器注释代码中的所有代码路径。在程序结束时,每个计数器将包含有关代码路径执行次数的信息。在Windows版本和Linux版本之间逐行比较这些数字可能显示该程序遵循不同的代码路径。根据代码路径的性质,差异可能能够解释为什么Linux版本比Windows版本慢。
int count[100];
// Call this function at the end of program
void PrintCounts() {
int i;
for(i=0; i<100; i++) printf("%d\n", count[i]);
}
void Flush_Buffer(int N) {
int Incnt;
ld->Bfr <<= N;
Incnt = ld->Incnt -= N;
if (Incnt <= 24) {
count[0]++;
if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4)) {
count[1]++;
do {
count[2]++;
...