4

我有一些用英特尔 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 中没有找到有关此术语的有用信息。

4

3 回答 3

9

您编写 Fortran 语句。英特尔 Fortran 编译器将这些语句翻译成汇编程序,包括对系统函数的调用。例如,strncmp是一个比较部分字符串的 ISO C 标准函数。所以看起来您正在编写 Fortran 语句来比较字符串,而英特尔 Fortran 编译器正在调用现有函数来实现比较。其中一些系统功能本身将(部分)通过调用您平台上提供的更基本功能来实现。

gprof正在向您显示对在您的编译产品中引用的函数的调用。您看到的大部分内容都是特定于 Linux I/O 的——在 Windows 机器上,I/O 将使用具有不同名称的类似功能。您看到的某些内容可能特定于英特尔编译器,所有英特尔编译器都对某些操作使用相同的(英特尔创建的)函数,并且该函数使用特定于平台的低级函数。

除非您准备重写这些低级函数,并冒着为使用相同函数的其他程序搞砸它们的风险,否则您可以做的唯一优化就是减少调用它们的频率。例如,如果您有理由认为读取文件末尾是一项昂贵的 I/O 操作,并且如果您的程序策略是读取文件直到您读取文件末尾然后处理出现的错误,那么您可能想要实施一个卓越的计划策略。这将比重写处理策略后果的低级 I/O 例程更容易。

于 2012-04-10T13:08:51.667 回答
3

假设您用任何语言编写以下内容

loop for a long time
  write something to somewhere

并使用gprof对其进行分析。

gprof在 IO 或任何其他阻塞状态期间暂停采样。这个程序做的很少,周期,但它确实花费的周期中,大部分都花在进出启动 IO 并等待它完成的内置库例程中。

因此,如果您的程序是这样的,那么您所看到的也就不足为奇了。

这个问题还有很多。

于 2012-04-10T19:52:46.617 回答
3

看起来您正在看到 Fortran I/O 操作。格式化的 I/O 在ifort. 如果使用标准输入/标准输出重定向,情况会更糟;更糟糕的是管道——英特尔文档特别警告不要这样做。gfortran几乎没有那么糟糕,但仍然很慢。

一些可能性是:

  • 尝试做尽可能少的 I/O 调用(例如将它们移出循环)
  • 避免重定向和直接读/写文件
  • checkblocksizebuffercount其他与 I/O 相关的选项open()

如果这还不够,并且 I/O 是您的主要瓶颈,您可以考虑:

  • 在 中查看流 I/O ifort,它更快,并且您可以自己做缓冲之类的事情,以避免进行多次调用。但是,它可能会引入可移植性问题,因为其他编译器可能还不支持它或以不同的方式执行它。不要在标准输入/输出上执行此操作(可能在 ifort 中工作,但它没有记录,并且不适用于其他编译器)。
  • 用于iso_c_binding调用 C 函数——例如,如果您正在写入标准输出,则可以puts()从 libc 调用。由于它是标准的,因此它甚至更快并且实际上非常便携,事实上,我在每个操作系统(Win32/linux64/sparc solaris)上完成的每个编译器都需要(并自动链接)libc;但它相当难看,而且您必须自己处理诸如空终止之类的事情(例如,通过编写包装函数),这会使代码变得模糊并可能导致错误。
  • 不要在同一个文件中将这些方法与常规 I/O 混合使用!!

If you are doing string comparisons explicitly in your code, these would eventually call strncmp() too. String operations are also a bit slow in ifort (although nowhere near as bad as I/O), so if you are doing A LOT of comparisons, you might gain a few seconds by calling strncmp() directly, but I would advice against that -- the gain is not that large, and again, it obscures the code.

于 2012-04-11T09:33:12.117 回答