热点循环优化-具体示例

以下是我正在开发的算法中最昂贵的部分。 到目前为止,绝对是一个热点-通过VisualVM检查。 经过一些优化技巧之后,例如展开3 ds行,就已经有了。 当然,由于GAUSS_POINT_WEIGHTS的元素数量固定为10,因此也可以尝试展开它,但这会产生100可能的组合,因此我不确定是否值得(也许无论如何,JIT都会做。)

for (int i = 0; i < mesh.getDofsY(); i++) {
      for (int k = 0; k < GAUSS_POINT_COUNT; k++) {
        val x = GAUSS_POINTS[k] * dx + leftSegment;
        for (int l = 0; l < GAUSS_POINT_COUNT; l++) {
          val wk = GAUSS_POINT_WEIGHTS[k];
          val wl = GAUSS_POINT_WEIGHTS[l];
          val gl = GAUSS_POINTS[l];
          val gk = GAUSS_POINTS[k];

          if (i > 1) {
            val y = (gl + (i - 2)) * dy;
            val v = wk * wl * b1.getvalue(gl) * problem.valueAt(x,y);
            ds.add(0,i,b3.getvalue(gk) * v);
            ds.add(1,b2.getvalue(gk) * v);
            ds.add(2,b1.getvalue(gk) * v);
          }
          if (i > 0 && (i - 1) < mesh.getElementsY()) {
            val y = (gl + (i - 1)) * dy;
            val v = wk * wl * b2.getvalue(gl) * problem.valueAt(x,b1.getvalue(gk) * v);
          }
          if (i < mesh.getElementsY()) {
            val y = (gl + i) * dy;
            val v = wk * wl * b3.getvalue(gl) * problem.valueAt(x,b1.getvalue(gk) * v);
          }
        }
      }
    }

在代码的这一部分中还有其他什么可以加速的(假设外部调用尽可能高效,这仅是关于此大量嵌套循环的事情)。我在问编译器特有的现象。

已经应用了下面的建议并有所帮助(请参阅pastebin),但似乎该热点中存在一个热点,它需要花费大量的计算时间或调用者循环(如上)。

problem.valueAt(x,y)转换为:

private double internalValueAt(double x,double y) {
    val ielemx = (long) (x / mesh.getDx());
    val ielemy = (long) (y / mesh.getDy());
    val localx = x - mesh.getDx() * ielemx;
    val localy = y - mesh.getDy() * ielemy;

    val sp1x = b1.getvalue(localx);
    val sp1y = b1.getvalue(localy);
    val sp2x = b2.getvalue(localx);
    val sp2y = b2.getvalue(localy);
    val sp3x = b3.getvalue(localx);
    val sp3y = b3.getvalue(localy);

    return coef.doubleValue(0,ielemy) * sp1x * sp1y +
        coef.doubleValue(0,ielemy + 1) * sp1x * sp2y +
        coef.doubleValue(0,ielemy + 2) * sp1x * sp3y +
        coef.doubleValue(1,ielemy) * sp2x * sp1y +
        coef.doubleValue(1,ielemy + 1) * sp2x * sp2y +
        coef.doubleValue(1,ielemy + 2) * sp2x * sp3y +
        coef.doubleValue(2,ielemy) * sp3x * sp1y +
        coef.doubleValue(2,ielemy + 1) * sp3x * sp2y +
        coef.doubleValue(2,ielemy + 2) * sp3x * sp3y;
  }

b1,b2 and b3与主循环(b样条曲线)中的功能相同。也许我可以从外面通过它们,但这值得吗?

在我看来,这方面无能为力,但是也许您可以发现值得做的事情?让我知道做某事是否有任何先决条件。

stpab 回答:热点循环优化-具体示例

展开100次非常疯狂,因为您的代码已经很长了。我敢打赌那里没有任何收获。相反只需单击“提取方法”,我就获得了巨大的提速(接近两倍)。

您可以在一个循环中取消wkgk初始化。

您也许可以通过提取wk * wl来避免某些乘法,但是我敢打赌,它还是被忽略了。

您可以通过拆分第一次和最后一次迭代来避免出现这种情况。

您可以在局部变量中缓存一些值(例如b3.getValue(gk))。

这只是猜测。无论如何,我将从提取最外层循环的主体开始,并测量是否存在速度差。希望它不会变得更糟,然后您可以轻松提取出第一和最后一个迭代。

对于中间迭代,有

val y = (gl + (i - 2)) * dy;
...
val y = (gl + (i - 1)) * dy;
...
val y = (gl + i) * dy;

可以递增计算。 JIT可能(最有可能)对整数执行此操作,但对浮点不执行此操作,因为它并不完全相同。对于您的val,我不知道是哪种情况。

然后,您可以将对ds.add(0,i,...)的三个调用汇总为ds.add(0,b3.getValue(gk) * (v + v' + v''),并将三个v从 三个if

本文链接:https://www.f2er.com/3089531.html

大家都在问