【发布时间】:2012-12-07 21:14:10
【问题描述】:
数周以来,我一直在与自己编写的翻译不佳的翻译作斗争。 在以下简单的基准上
#include<stdio.h>
int main()
{
int x;
char buf[2048];
FILE *test = fopen("test.out", "wb");
setvbuf(test, buf, _IOFBF, sizeof buf);
for(x=0;x<1024*1024; x++)
fprintf(test, "%04d", x);
fclose(test);
return 0
}
我们看到以下结果
bash-3.1$ gcc -O2 -static test.c -o test
bash-3.1$ time ./test
real 0m0.334s
user 0m0.015s
sys 0m0.016s
如您所见,在添加“-std=c99”标志的那一刻,性能就会崩溃:
bash-3.1$ gcc -O2 -static -std=c99 test.c -o test
bash-3.1$ time ./test
real 0m2.477s
user 0m0.015s
sys 0m0.000s
我使用的编译器是 gcc 4.6.2 mingw32。
生成的文件大约12M,所以这两者之间的差异大约是21MB/s。
运行diff 显示生成的文件是相同的。
我认为这与fprintf 中的文件锁定有关,该程序大量使用其中的文件,但我无法在 C99 版本中找到关闭它的方法。
我在程序开头使用的流上尝试了flockfile,并在最后尝试了相应的funlockfile,但遇到了关于隐式声明的编译器错误,以及声称对这些函数的未定义引用的链接器错误。
这个问题能不能有其他解释,更重要的是,有没有什么方法可以在windows上使用C99而不需要付出如此巨大的性能代价?
编辑:
查看这些选项生成的代码后,看起来在慢版本中,mingw 坚持如下:
_fprintf:
LFB0:
.cfi_startproc
subl $28, %esp
.cfi_def_cfa_offset 32
leal 40(%esp), %eax
movl %eax, 8(%esp)
movl 36(%esp), %eax
movl %eax, 4(%esp)
movl 32(%esp), %eax
movl %eax, (%esp)
call ___mingw_vfprintf
addl $28, %esp
.cfi_def_cfa_offset 4
ret
.cfi_endproc
在快速版本中,这根本不存在;否则,两者完全相同。我认为__mingw_vfprintf 似乎是这里的慢动作,但我不知道它需要模拟什么行为让它变得如此缓慢。
【问题讨论】:
-
您需要将问题分解为一个完整的您可以实际发布的代码的工作示例,让人们推测您可能做了什么并不是很有效率。跨度>
-
注释掉 printf 并重新测试,看看这是否真的是差异的根源。
-
@unwind 我很抱歉;我确信问题出在
printf我违反了这个网站的基本规则。我什至没有想到问题会出在其他地方。 -
快速版本的汇编器呢?这将有助于比较。
-
好的,所以
_fprintf在快速版本中不存在。但是,主循环是什么样的呢?
标签: c performance locking stdio mingw32