【问题标题】:fortran90: addressing memory locationfortran90:寻址内存位置
【发布时间】:2014-10-13 11:19:15
【问题描述】:

我有一个 fortran90 代码要优化。 现在我想在外部循环中访问结构的内存位置,然后在嵌套循环中访问最深的结构。 像这样的:

fortran 循环示例 - 旧版

do i = 1, N
  ii = some integer
  jj = some other integer
  do j = 1, M
    c = a(ii, jj)%b(i)
  enddo
enddo

必须变成:

第二个fortran循环——我想写什么

do i = 1, N
  ii = some integer
  jj = some other integer
  pointertoa = &a(ii, jj) !I know it's not correct in fortran, that is the question!
  do j = 1, M
    c = pointertoa%b(i)
  enddo
enddo

我有这个(示例)C 代码按预期工作:

C 中的工作内存寻址

#include <stdio.h>

struct mem{
  int a;
    struct mm{
    int b;
    float v;
  } mmm;
};

void main(){

  struct mem *m, dum;

  dum.a = 12;
  dum.mmm.b = 5;
  dum.mmm.v = 3.2;

  m = &dum; //m is given dum memory address

  printf("dum.a = %d\n", dum.a);
  printf("dum.mmm.b = %d\n", dum.mmm.b);
  printf("dum.mmm.v = %f\n", dum.mmm.v);

  printf("m.a = %d\n", m->a);
  printf("m.mmm.b = %d\n", m->mmm.b);
  printf("m.mmm.v = %f\n", m->mmm.v);

}

几个问题:

  1. 你会如何做我在 fortran90 中用 C 做的同样的事情?
  2. 您认为第二个 fortran 循环会加快代码速度吗?

【问题讨论】:

  • 关于(2)如何加速代码?
  • Fortran 中的指针由=&gt; 设置,而不是&amp;
  • @JohnZwinck,加速将是一种预取:您可以看到iijj 索引存储在外部循环中,所以它会是很明显在同一个地方加载a(ii, jj)。 @AlexanderVogt,指针根本行不通,因为我需要 a(ii, jj) 在内部循环中的内存位置,而不是对其值的引用-无论如何,我尝试在 C 代码中使用指针,得到一个设置错误:)。
  • @bio,编译器并不笨,首先证明这确实会减慢代码速度,然后才能优化。
  • 好吧,我说的似乎不正确:我得到 seg 错误的原因是我在写*m = dum 之前没有分配*m。此代码产生正确的输出:m = malloc(sizeof (struct mem)); *m = dum; 谢谢!

标签: c pointers fortran90 memory-address


【解决方案1】:

Fortran 将使您很难获得变量的内存地址或其他任何东西。您可能在 C 中学到的技巧和技术,包括指针和内存地址,在 Fortran 中不受支持。通常,在 Fortran 的核心应用程序域中也不需要它们。您的问题反而表明您正在尝试用 Fortran 编写 C。不要。

现在我已经明白了,您也许可以使用最近引入的 associate 构造来实现您想要的。像

  associate(pointertoa => a(ii, jj)) 
  do j = 1, M
    c = pointertoa%b(i)
  enddo
  end associate

这是否能实现您的效率目标我没有史酷比。但如果是这样,我会感到惊讶。优化对数组元素的访问是 Fortran 编译器 50 多年来一直在努力的事情,而且他们真的很擅长。

编辑,回应 OP 的第一条评论...

如果您的编译器支持associate,您当然可以使用它。但是,如果您使用在 90 标准发布后引入 Fortran 的任何功能,有人会越过您的肩膀并痛击您的头部,那么您是否接受打击取决于您。编译器不会关心,编译后的代码也不会关心。 associate 是标准的一部分,Fortran 在保持向后兼容性方面有着非常好的记录,因此未来的编译器出现故障的可能性非常小。

在编写您的 C 函数时,不要忘记利用循环展开、内存预取、多指令流水线、向量操作、公共子表达式消除等所有这些东西。如果你设法编写了一个 C 函数,它的性能优于 Fortran 编译器的产品,优化高达 11,请返回数据来证明这一点,我会吃掉我的帽子。

而且,当我再次写作时,我注意到循环

  do j = 1, M
    c = pointertoa%b(i)
  enddo

几乎完全是多余的,一个好的优化编译器只会创建代码来执行一次c = pointertoa%b(i)

【讨论】:

  • 看来associate 是在 fortran 2003 中引入的东西。不幸的是,我必须优化 fortran90 代码!我可以在fortran90中使用它吗?我想我会尝试编写一个外部 C 函数来完成这项工作。关于效率,您对编译器的聪明程度是正确的,但是正如我对以前的 cmets 的回答,如果我愿意,我会减少 M 的负载。
  • 您也可以只使用 Fortran 90 指针:type(xx), ponter :: pointertoa; pointertoa =&gt; a(ii, jj),但我实际上预计代码效率会降低,而不是提高。编译器足够聪明,他们发现自己不必多次计算a(ii, jj) 的地址。
  • @HPM,非常感谢。我按照 Vladimir 的建议使用了 Fortran 90 指针,但没有得到显着的改进。仍然需要阅读优化报告(使用带有 -O3 标志的 ifort 15),但我肯定没有加速。当然,我正在使用任何技术来加速这段代码,并且已经看到了向量化标志的真正改进,但后来我决定退后一步,看看串行标量代码是否是我能做到的最好的有。你可以戴上帽子:)
猜你喜欢
  • 2016-03-07
  • 2011-03-12
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 2012-01-07
  • 2010-11-24
相关资源
最近更新 更多