Fortran暗示写加速

时间:2016-02-09 21:06:45

标签: performance io fortran

tl; dr :我发现在某些情况下,“隐含的”写入比明确的写入慢,并且想要理解为什么/如果我可以改进它。

详情
我有一个代码可以起到以下作用:

DO i=1,n
  calculations...

  !m, x, and y all change each pass through the loop
  IF(m.GT.1)THEN   
    DO j=1,m
      WRITE(10,*)x(j),y(j)  !where 10 is an output file
    ENDDO
  ENDIF
ENDDO

输出文件最终相当大,所以看起来写作是一个很大的性能因素,所以我想优化它。在任何人要求之前,不,由于各种下游要求,远离ASCII不是一种选择。因此,我将IF语句(和内容)重写为:

IF(m.GT.1)THEN
  !build format statement for write
  WRITE(mm1,*)m-1
  mm1=ADJUSTL(mm1)
  !implied do write statement
  WRITE(10,'('//TRIM(mm1)//'(i9,1x,f7.5/),i9,1x,f7.5)')(x(j),y(j),j=1,m)
ELSEIF(m.EQ.1)THEN
  WRITE(10,'(i9,1x,f7.5)')x(1),y(1)
ENDIF

这将根据要写出的值的#构建格式语句,然后执行单个write语句来输出内容。我发现使用这个公式代码实际运行速度较慢。作为参考,当要写入的数据量固定时,我在同一系统(硬件和软件)上看到了显着的加速。假设WRITE语句本身更快,那么这意味着构建该语句的几行的开销会增加时间,但这似乎很难相信。作为参考,m可能会有相当大的变化,但可能平均至少为1000.字符串//的串联是一个非常慢的运算符,还是我还缺少其他东西?提前致谢。

1 个答案:

答案 0 :(得分:2)

我还没有添加具体的时序信息,但是使用隐含的do循环进行数据传输是不必要的复杂。

在第一个片段中,使用显式循环,您将每对数字写入不同的记录,并希望使用隐含的do循环重复此输出。为此,您可以使用斜杠编辑描述符在写入一对后终止每个记录。

不必要的复杂性来自两个方面:

  • 你有一个/多个对的不同案例;
  • 对于多于一种情况,您构建的格式包括"动态"重复计数。

作为Vladimir F comments,您可以使用非常大的重复计数:当没有更多项目要写入时,处理编辑描述符并不是错误的。当到达这样的非匹配描述符时,输出终止(成功)。那你可以写一下

 WRITE(10,'(*(i9,1x,f7.5/))') (x(j),y(j),j=1,m)  ! * replacing a large count

而不是if构造和格式创建。

现在,这与您的第一个输出完全匹配。如上所述,当没有相应的项目要输出时,在到达数据编辑描述符时会出现输出终止。这意味着/将在此之前得到处理:您有一个最终的空记录。

冒号编辑描述符在这里很有用:

 WRITE(10,'(*(i9,1x,f7.5,:,/))') (x(j),y(j),j=1,m)

如果没有要处理的剩余输出项,则在达到:处理时立即停止。

但我的首选方法是更简单的

 WRITE(10,'(i9,1x,f7.5)') (x(j),y(j),j=1,m) ! No repeat count

您有更详细的格式来​​包含记录终止。但是,我们有所谓的格式返回:如果达到格式结束并且还有更多要输出,那么记录将被终止,处理将返回到格式的开头。

这些东西是否能让你的输出更快还有待观察,但它们肯定会使代码本身更清晰,更清晰。

作为最后一点,它曾经很时髦,以避免额外的X编辑。如果您的数字适合宽度为7的字段,则1x,f7.5可以替换为f8.5并具有相同的外观:表示在字段中是右对齐的。据称,这种减少具有性能优势,而且描述符的切换次数更少。