考虑以下代码片段
double *x, *id;
int i, n; // = vector size
// allocate and zero x
// set id to 0:n-1
for(i=0; i<n; i++) {
long iid = (long)id[i];
if(iid>=0 && iid<n && (double)iid==id[i]){
x[iid] = 1;
} else break;
}
该代码使用向量id
类型中的值作为向量的double
索引x
。为了使索引有效,我验证它们大于或等于 0,小于向量大小 n,并且存储的双精度id
数实际上是整数。在此示例中,存储了从 1 到 n 的整数,因此所有向量都是线性访问的,并且语句id
的分支预测应该始终有效。if
因为n=1e8
代码在我的电脑上需要 0.21 秒。由于在我看来它是一个计算量轻的循环,我希望它是内存带宽有限的。根据基准内存带宽,我预计它可以在 0.15 秒内运行。我将内存占用计算为每个值 8 个字节id
,每个值 16 个字节x
(它需要同时写入和从内存中读取,因为我假设不使用 SSE 流)。所以每个向量条目总共有 24 个字节。
问题:
- 我错说这段代码应该是内存带宽限制的,并且可以改进吗?
- 如果没有,您知道我可以提高性能以使其与内存速度一起工作的方法吗?
- 或者也许一切都很好,除了并行运行它之外,我无法轻易改进它?
改变的类型id
不是一种选择——它必须是double
。此外,在一般情况下id
,x
具有不同的大小并且必须作为单独的数组保存 - 它们来自程序的不同部分。简而言之,我想知道是否可以以更有效的方式编写绑定检查和类型转换/整数验证。
为方便起见,整个代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static struct timeval tb, te;
void tic()
{
gettimeofday(&tb, NULL);
}
void toc(const char *idtxt)
{
long s,u;
gettimeofday(&te, NULL);
s=te.tv_sec-tb.tv_sec;
u=te.tv_usec-tb.tv_usec;
printf("%-30s%10li.%.6li\n", idtxt,
(s*1000000+u)/1000000, (s*1000000+u)%1000000);
}
int main(int argc, char *argv[])
{
double *x = NULL;
double *id = NULL;
int i, n;
// vector size is a command line parameter
n = atoi(argv[1]);
printf("x size %i\n", n);
// not included in timing in MATLAB
x = calloc(sizeof(double),n);
memset(x, 0, sizeof(double)*n);
// create index vector
tic();
id = malloc(sizeof(double)*n);
for(i=0; i<n; i++) id[i] = i;
toc("id = 1:n");
// use id to index x and set all entries to 4
tic();
for(i=0; i<n; i++) {
long iid = (long)id[i];
if(iid>=0 && iid<n && (double)iid==id[i]){
x[iid] = 1;
} else break;
}
toc("x(id) = 1");
}