【问题标题】:Optimize mathematical expressions优化数学表达式
【发布时间】:2015-04-03 04:33:30
【问题描述】:

我对 fitch 软件花费多少时间来进行一些简单的计算感到沮丧。我使用 Intel VTune 对其进行了分析,似乎 52% 的 CPU 时间都花在了 nudists() 函数上:

void nudists(node *x, node *y)
{
  /* compute distance between an interior node and tips */
  long nq=0, nr=0, nx=0, ny=0;
  double dil=0, djl=0, wil=0, wjl=0, vi=0, vj=0;
  node *qprime, *rprime;

  qprime = x->next;
  rprime = qprime->next->back;
  qprime = qprime->back;
  ny = y->index;
  dil = qprime->d[ny - 1];
  djl = rprime->d[ny - 1];
  wil = qprime->w[ny - 1];
  wjl = rprime->w[ny - 1];
  vi = qprime->v;
  vj = rprime->v;
  x->w[ny - 1] = wil + wjl;
  if (wil + wjl <= 0.0)
    x->d[ny - 1] = 0.0;
  else
    x->d[ny - 1] = ((dil - vi) * wil + (djl - vj) * wjl) / (wil + wjl);
  nx = x->index;
  nq = qprime->index;
  nr = rprime->index;
  dil = y->d[nq - 1];
  djl = y->d[nr - 1];
  wil = y->w[nq - 1];
  wjl = y->w[nr - 1];
  y->w[nx - 1] = wil + wjl;
  if (wil + wjl <= 0.0)
    y->d[nx - 1] = 0.0;
  else
    y->d[nx - 1] = ((dil - vi) * wil + (djl - vj) * wjl) / (wil + wjl);
}  /* nudists */

两条长线占用了总 CPU 时间的 24%。有什么办法可以优化这段代码,尤其是两条长线?另一个消耗大量 CPU 时间的函数是:

void secondtraverse(node *q, double y, long *nx, double *sum)
{
  /* from each of those places go back to all others */
   /* nx comes from firsttraverse */
   /* sum comes from evaluate via firsttraverse */
  double z=0.0, TEMP=0.0;

  z = y + q->v;
  if (q->tip) {
    TEMP = q->d[(*nx) - 1] - z;
    *sum += q->w[(*nx) - 1] * (TEMP * TEMP);
  } else {
    secondtraverse(q->next->back, z, nx, sum);
    secondtraverse(q->next->next->back, z, nx,sum);
  }
}  /* secondtraverse */

计算总和的代码占 CPU 时间的 18%。有什么办法让它跑得更快?

完整的源代码可以在这里找到:http://evolution.genetics.washington.edu/phylip/getme.html

【问题讨论】:

  • 跑题了,但是为什么你的函数叫nudists
  • 除了改进算法的大 O 之外,优化可能是一门黑暗的艺术。正确的方法通常是修改、分析、重复。如果你能读懂反汇编,那就更好了。您可以通过一些技巧来消除 if/else 分支。您可以通过预先计算 1.0 / (wil + wjl) 来消除多余的划分。
  • 我不知道 - 不是我写了这个软件。这是开源的。
  • @PhilipStuyck:不,随机抓取一段您没有编写且不理解的代码并要求其他人对其进行优化是无效的。向下投票箭头表示“这个问题显示出很少的研究努力”,似乎就是这种情况。 OP 没有尝试解决他自己的问题(尽管识别热点是一个很好的步骤)
  • @BenVoigt 不确定我是否同意他是否通过分析器运行它并能够在无数其他函数中将此函数确定为罪魁祸首我会说这表明了研究工作。但我可能是错的,如果他只是从那个链接上拿的......

标签: c++ c optimization


【解决方案1】:

就优化大方程线而言,您正在使用一些最耗时的运算:乘法和除法。

您将不得不在更大的框架、图片或范围内寻找优化。一些想法:

  • 定点算法
  • 消除每次迭代的除法。
  • 线程
  • 多核
  • 数组,非链表

定点算术

如果您可以将数字基数设为 2 的幂,则您的许多除法将变为位移位。例如,除以 16 与右移 4 次相同。班次通常比分班快。

每次迭代消除除法

与其在每次迭代中执行除法,不如将其提取出来并减少执行频率,也许使用不同的值。

如果您将除法视为分数,您可以在除以分母之前多次使用分子。

线程

您可能需要考虑多个线程。根据代码效率创建线程。让一个线程成为在后台计算的工作线程。

多核(并行执行)

“x”和“y”变量看起来是相互独立的。这些计算可以设置为并行编程。一个核心或处理器执行“x”计算,而另一个核心正在计算“y”变量。

考虑在更高的层次上拆分它。一个核心(线程)处理所有“x”变量,而另一个核心处理“y”变量。结果独立保存。在计算完所有“x”和“y”变量后,让主核心处理所有结果。

数组,而不是列表

当所有数据都可以放入处理器的数据缓存时,您的处理器将是最快乐的。如果不能拟合所有数据,则尽可能拟合。因此,与链表相比,数组最有可能适合数据缓存行。处理器将知道一个数组地址是连续的,并且可能不必重新加载数据缓存。

【讨论】:

    猜你喜欢
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 2017-12-28
    • 2012-07-13
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多