有什么快速访问内存的技巧吗

Is there any tricks for fast-memory access?

本文关键字:内存 访问 什么      更新时间:2023-10-16

我对C++编程世界很陌生,很抱歉问我一个业余问题:

我在主存储器(1-D阵列)中存储了一大块数据,我需要经常访问那里的一些数据,我的方法是:

float *x=new float[20];//array to store x;
int *indlistforx=new int[20];//array to store the index of x;
float *databank=new float[100000000];//a huge array to store data
/... fill data to databank.../

for (int i=0;i<N;i++)//where N is a very large number;
{
/... write index to indlistforx.../
getdatafromdatabank(x, indlistforx, databank);
//Based on the index provided by indlistforx, read data from databank then pass them to x
/...do something with x.../
};

是否有任何有效/快速的方法来访问这些数据(x的索引没有对齐,也不可能对齐)?

非常感谢!

您还没有真正展示如何访问数据库,所以这一切都是推测性的:

  • indlistforx是数据库中20个索引的列表吗?所以您正在进行20次随机访问?

    • 这些指数的步幅是什么:它们是连续的,还是紧密相连的,还是随机的
    • 如果它们是连续的或相近的,则对它们进行排序可能会有所帮助(因此,您将按升序读取以改进预取,并将来自同一缓存行的读取分组在一起)
  • 不同的20个指数组的波动幅度有多大?它们能重叠吗?

    • 如果它们不能重叠,那么数据库被有效地划分为一些块大小,那么在不同的处理器上处理每个分区可能会增加您可以使用的有效缓存量(如果您有多个处理器)
    • 如果请求可以重叠,那么如果数据库是只读的,则并发运行它们仍然可以工作。如果有任何内容写入数据库,这将成为缓存抖动的处方
  • 你能在更高的级别上重新排序访问以获得更好的缓存行为吗:更有序、更好的引用空间或时间位置?

    • 这与我的第一个建议基本相同,但高于单个indlistforx请求的级别
    • 类似地,考虑对它们进行重新排序以有效地对数据库进行分区,并尝试多处理器的想法

如果看不到所有的代码(或者一个有代表性的示例,我知道这可能太大了),就很难再详细介绍了。

然而,有一种通用技术可能会奏效。。。它也可能是如此沉重,以至于实现成本超过了节省的成本。

  • 让你的getfromdatabank返回一个future/preet/whatever,而不是同步完成(或者20个futures的向量,如果不是太细粒度的话)
  • 尝试并行地调度许多这样的异步请求,要么在单独的线程中(访问未来将是一个阻塞操作),要么使用事件循环来处理类似显式协同例程的完成
  • 有一个专用线程聚合来自多个请求的所有数据库访问,并对它们进行重新排序以获得更好的缓存性能

只有当额外的同步开销由改进的读取性能所支配,并且您可以有效地并行运行许多查询时,这才能起作用。

由于需要初始化float,因此实际上应该使用std::vector<>,它并不慢,像这样构建和填充:

std::vector< float > databank( 100000000, 0.0f );

有几个加速选项:

1) 如果有一个相当大的键(索引)重用,那么您可以使用某种缓存或记忆策略。看见http://www.boost.org/doc/libs/1_51_0/libs/flyweight/doc/index.html例如。

2) 您可以使用std::async()将处理拆分为多个线程。

3) 确保编译器已打开simd指令(x86上的sse)并正在使用它们。如果没有,则使用编译器内部函数强制使用simd。这将使性能提高近4倍。

问题不在于如何表示databank。问题在于你是如何使用它的。在短时间内随机访问databank中相距甚远的部分会影响你的性能。你的getdatafromdatabank(x, indlistforx, databank)和那个indlistforx几乎保证了糟糕的性能。indlistforx启用的随机访问带来了显著的性能损失。如果随机访问是绝对必要的,因为使用databank的算法是如何工作的,那么这只是你必须付出的代价。

如果您可以修改算法,使其访问databank中的连续内存块,那么您将获得更好的性能。更改getdatafromdatabank,以便仅指定第一个索引(要加载到x[0]中的元素的索引),而不是数组20索引。

x的大小为20是有原因的吗?如果勉强将输出x数组和databank的相关块保留在级别1缓存中,您将获得最佳性能。如果x的大小增加超过此最佳大小,则性能将开始下降,并且可能会显著下降。