我很沮丧fitch软件花了多少时间做一些简单的计算。我使用英特尔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
答案 0 :(得分:1)
就优化大方程线而言,您正在使用一些最耗时的操作:乘法和除法。
您必须在更大的框架,图片或范围内寻找优化。一些想法:
如果您可以使数字基数为2的幂,那么您的许多分区将变为位移。例如,除以16与右移4次相同。转移通常比分裂更快。
不是在每次迭代中执行除法,而是将其解压缩并更少地执行,可能使用不同的值。
如果将除法视为分数,则可以在除以分母之前多次使用分子。
您可能需要考虑多个线程。根据代码效率创建线程。让一个线程成为在后台计算的工作线程。
&#39; x&#39;并且&#39; y&#39;变量似乎彼此独立。可以为并行编程设置这些计算。一个核心或处理器执行&#39; x&#39;计算,而另一个核心是计算&#39; y&#39;变量。
考虑将其拆分为更高级别。一个核心(线程)处理所有&#39; x&#39;变量,而另一个核心处理&#39; y&#39;变量。结果独立保存。让主核心在所有&#39; x&#39;之后处理所有结果。并且&#39; y&#39;变量已经计算出来。
当所有数据都适合处理器的数据缓存时,您的处理器将会非常开心。如果它不能适合所有数据,那么尽可能适合。因此,与链表相比,数组最适合数据缓存行。处理器将知道阵列地址是顺序的,并且可能不必重新加载数据高速缓存。