我有一些使用intel fortran编译器ifort编译的fortran代码。当我使用gprof进行配置文件测试时,我得到的大部分时间用于IO操作,我想找到文件的结尾,但我找不到更多关于此的文档:
index % time self children called name
<spontaneous>
[1] 20.6 0.07 0.00 _IO_wfile_seekoff [1]
-----------------------------------------------
<spontaneous>
[2] 20.6 0.07 0.00 sforcepf_ [2]
-----------------------------------------------
<spontaneous>
[3] 20.6 0.02 0.05 _IO_wfile_underflow [3]
0.01 0.04 258716/258717 strncmp [4]
-----------------------------------------------
0.00 0.00 1/258717 _IO_wdefault_doallocate [15]
0.01 0.04 258716/258717 _IO_wfile_underflow [3]
[4] 14.7 0.01 0.04 258717 strncmp [4]
0.04 0.00 3104592/3109256 strerror_r [5]
-----------------------------------------------
0.00 0.00 4664/3109256 __strcmp_sse42 [14]
0.04 0.00 3104592/3109256 strncmp [4]
[5] 11.8 0.04 0.00 3109256 strerror_r [5]
-----------------------------------------------
所以,问题是,这个IO是针对Linux,还是针对ifort,还是针对fortran?我正在尝试优化此代码,并且在google中找不到有关此术语的有用信息。
答案 0 :(得分:9)
您编写Fortran语句。英特尔Fortran编译器将这些语句转换为汇编程序,包括对系统函数的调用。例如,strncmp
是ISO C标准函数,用于比较字符串的各个部分。因此,看起来您正在编写Fortran语句来比较字符串,而英特尔Fortran编译器正在调用现有函数来实现比较。其中一些系统功能本身将通过调用平台上提供的更基本功能来实现(部分)。
gprof
向您显示对编译产品中引用的函数的调用。您看到的大部分内容都特定于Linux I / O - 在Windows机器上,I / O将使用具有不同名称的类似功能。您看到的一些内容可能是英特尔编译器特有的,所有英特尔编译器都使用相同的(英特尔创建的)功能进行某些操作,并且该功能使用特定于平台的低级功能。
除非你准备重写这些低级函数,并冒着使用相同函数将其搞砸到其他程序的风险,否则你可以做的唯一优化就是不经常调用它们。例如,如果您有理由认为读取文件末尾是一项昂贵的I / O操作,并且您的程序策略是读取文件,直到您阅读结束然后处理出现的错误,那么你可能想要实施一个优秀的计划战略。这比重写低级I / O例程更容易,后者处理策略的后果。
答案 1 :(得分:3)
假设您使用任何语言编写以下内容
loop for a long time
write something to somewhere
并使用 gprof 对其进行分析。
gprof 在IO或任何其他阻塞状态期间暂停采样。 这个程序执行的时间非常短,但是它所花费的周期很多,其中大部分用于进入和退出启动IO并等待它完成的内置库例程。
因此,如果您的计划是这样的,那么您所看到的内容就不足为奇了。
答案 2 :(得分:3)
看起来您正在看Fortran I / O操作。 ifort
格式化的I / O非常慢。如果使用标准输入/标准输出重定向,则会更糟;管道更糟糕 - 英特尔专家警告不要这样做。 gfortran
并不是那么糟糕,但仍然很慢。
一些可能性是:
blocksize
buffercount
,open()
和其他与I / O相关的选项
如果这还不够,I / O是您的主要瓶颈,您可以考虑:
ifort
中查看流I / O,它更快,你可以做一些事情,比如自己缓冲,以避免多次通话。但是,它可能引入可移植性问题,因为其他编译器可能还不支持它或者以不同方式执行它。不要在标准输入/输出上执行(可能在ifort中工作,但它没有记录,并且不能与其他编译器一起使用)。iso_c_binding
调用C函数 - 例如如果您要写入标准输出,可以从libc调用puts()
。这是更快,实际上非常便携,因为它是标准的,事实上,我所做的每个操作系统上的每个编译器(Win32 / linux64 / sparc solaris)都需要(并自动链接)libc;但它相当丑陋,你必须自己处理诸如null终止之类的事情(例如通过编写包装器函数),这会掩盖代码并导致错误。 如果您在代码中明确进行字符串比较,这些最终也会调用strncmp()
。 ifort中的字符串操作也有点慢(虽然远不如I / O那么糟),所以如果你正在做 A LOT 的比较,你可能会通过调用{{1}来获得几秒钟直接,但我建议反对 - 增益不是那么大,再次,它掩盖了代码。