7

我有一个问题....我在while循环中将数据写入数组。关键是我经常这样做。看来,这种写作现在是代码中的瓶颈。所以我认为这是由写入内存引起的。这个数组并不是很大(比如 300 个元素)。问题是可以这样做:仅在while循环完成后将其存储在缓存中并在内存中更新?

[编辑 - 复制自 Alex 添加的答案]

double* array1  = new double[1000000]; // this array has elements  
unsigned long* array2  = unsigned long[300];
double varX,t,sum=0;
int iter=0,i=0;
while(i<=max_steps)
{
   varX+=difX;
   nm0 =  int(varX);
   if(nm1!=nm0)
   {
        array2[iter] = nm0;  // if you comment this string application works more then 2 times faster :)
        nm1=nm0;
        t = array1[nm0]; // if you comment this string , there is almost no change in time 
        ++iter;
   }
   sum+=t;
   ++i;
}

首先我要感谢大家的回答。确实,不输入代码有点愚蠢。所以我决定现在就去做。

double* array1  = new double[1000000]; // this array has elements  
unsigned long* array2  = unsigned long[300];
double varX,t,sum=0;
int iter=0,i=0;
while(i<=max_steps)
{
   varX+=difX;
   nm0 =  int(varX);
   if(nm1!=nm0)
   {
        array2[iter] = nm0;  // if you comment this string application works more then 2 times faster :)
        nm1=nm0;
        t = array1[nm0]; // if you comment this string , there is almost no change in time 
        ++iter;
   }
   sum+=t;
   ++i;
}

就是这样。如果有人有任何想法,那就太好了。再一次非常感谢你。

真诚的亚历克斯

4

12 回答 12

12

不是故意的,不是。除其他外,您不知道缓存有多大,因此您不知道要适应什么。此外,如果允许应用程序锁定部分缓存,对操作系统的影响可能会对整体系统性能造成毁灭性影响。这完全属于我的“你不能这样做,因为你不应该这样做。永远”的清单。

您可以做的是改善您的参考位置 - 尝试安排循环,以便您不会多次访问元素,并尝试在内存中按顺序访问它们。

如果没有关于您的申请的更多线索,我认为无法给出更具体的建议。

于 2009-10-06T14:22:41.737 回答
8

CPU 通常不提供细粒度的缓存控制,您不能选择要驱逐的内容或将内容固定在缓存中。您在某些 CPU 上确实有一些缓存操作。就像一些关于你可以做什么的信息:这里有一些关于较新的 x86{-64} CPU 的有趣的缓存相关指令(做这样的事情会使可移植性变得糟糕,但我想你可能会好奇)

软件数据主管

非临时指令是prefetchnta,它将数据取到二级缓存中,最大限度地减少缓存污染。

临时指令如下:

* prefetcht0 – fetches the data into all cache levels, that is, to the

Pentium® 4 处理器的二级缓存。

* prefetcht1 – Identical to prefetcht0

* prefetcht2 – Identical to prefetcht0

此外,还有一组指令用于访问内存中的数据,但明确告诉处理器不要将数据插入缓存。这些被称为非临时指令。一个例子在这里:MOVNTI

您可以对您不希望缓存中的每条数据使用非临时指令,希望其余部分始终保留在缓存中。我不知道这是否真的会提高性能,因为在缓存方面需要注意一些微妙的行为。而且听起来这样做会比较痛苦。

于 2009-10-06T14:48:33.930 回答
4

我有一个问题....我在while循环中将数据写入数组。关键是我经常这样做。看来,这种写作现在是代码中的瓶颈。所以我认为这是由写入内存引起的。这个数组并不是很大(比如 300 个元素)。问题是可以这样做:仅在while循环完成后将其存储在缓存中并在内存中更新?

你不需要。它可能被推出缓存的唯一原因是如果认为其他一些数据更紧急放入缓存。

除此之外,一个包含 300 个元素的数组应该可以毫无问题地放入缓存中(假设元素大小不是太疯狂),因此很可能您的数据已经在缓存中。

无论如何,最有效的解决方案可能是调整您的代码。使用大量临时变量(向编译器指示内存地址并不重要),而不是不断地写入/读取数组。重新排序您的代码,以便在循环开始时执行一次加载,并尽可能分解依赖链。

手动展开循环可以让您更灵活地实现这些目标。

最后,您应该使用两个明显的工具,而不是猜测缓存行为:

  • 探查器和缓存研磨(如果可用)。一个好的分析器可以告诉你很多关于缓存未命中的统计数据,并且 cachegrind 也可以给你很多信息。
  • 我们在 StackOverflow。如果您发布循环代码并询问如何改进其性能,我相信我们中的很多人都会发现这是一个有趣的挑战。

但正如其他人所提到的,在处理性能时,不要猜测。您需要可靠的数据和测量结果,而不是预感和直觉。

于 2009-10-06T17:25:07.457 回答
3

除非您的代码在写入数组之间做一些完全不同的事情,否则大部分数组可能会保存在缓存中。

不幸的是,除了在考虑缓存的情况下重写算法之外,您无法做任何事情来影响缓存中的内容。尝试在写入内存之间使用尽可能少的内存:不要使用大量变量,不要调用许多其他函数,并尝试连续写入数组的同一区域。

于 2009-10-06T14:23:13.550 回答
2

在这种情况下,array2将非常“热”并仅出于这个原因而留在缓存中。诀窍是远离array1缓存(!)。你只读过一次,所以缓存它没有意义。SSE 指令是MOVNTPD内在的void_mm_stream_pd(double *destination, __m128i source)

于 2009-10-07T12:29:54.163 回答
2

我怀疑这是可能的,至少在高级多任务操作系统上是这样。您不能保证您的进程不会被抢占,并失去 CPU。如果你的进程拥有缓存,其他进程就不能使用它,这会使它们的执行速度非常慢,并使事情变得非常复杂。您真的不想运行没有缓存的现代几GHz 处理器,只是因为一个应用程序已将所有其他应用程序锁定在它之外。

于 2009-10-06T14:21:33.503 回答
1

当你遇到性能问题时,不要假设任何事情,先测量。例如,注释掉写入,看看性能是否有任何不同。

如果您正在写入结构数组,请使用结构指针来缓存结构的地址,这样您就不会在每次访问时都对数组进行乘法运算。确保您使用数组索引器变量的本机字长以实现最大优化。

于 2009-10-06T15:19:41.827 回答
1

即使可以,这也是个坏主意。

现代台式计算机使用多核 CPU。英特尔的芯片是台式机中最常见的芯片……但 Core 和 Core 2 处理器不共享片上缓存。

也就是说,在 Core 2 i7 芯片发布之前没有共享缓存,它共享一个片上 8MB L3 缓存。

因此,如果您能够将数据锁定在我正在输入此内容的计算机上的缓存中,您甚至无法保证此进程将被安排在同一个核心上,因此缓存锁定可能完全没用。

于 2009-10-06T14:32:56.510 回答
1

如果您的写入速度很慢,请确保没有其他 CPU 内核同时在同一内存区域中写入。

于 2009-10-06T14:33:38.520 回答
1

可能可以使用一些汇编代码,或者正如有人指出的,汇编内在函数,将内存行预取到缓存中,但这将花费大量时间来修补它。

只是为了试验,尝试读入所有数据(以编译器不会优化的方式),然后进行写入。看看是否有帮助。

于 2009-10-06T14:36:06.300 回答
1

正如其他人所说,您无法直接控制它,但更改代码可能会间接启用更好的缓存。如果您在 linux 上运行,并希望在程序运行时更深入地了解 CPU 缓存发生了什么,您可以使用 Cachegrind 工具,它是Valgrind套件的一部分。这是一个处理器的模拟,所以它并不完全真实,但它为您提供了其他任何方式都难以获得的信息。

于 2009-10-06T15:31:13.317 回答
1

在 CoreBoot(以前称为 LinuxBIOS)的早期启动阶段,因为他们还无法访问 RAM(我们正在谈论 BIOS 代码,因此 RAM 尚未初始化),他们设置了一些他们称之为 Cache-as-RAM 的东西( CAR),即即使没有实际 RAM 支持,它们也将处理器缓存用作 RAM。

于 2011-02-01T18:12:39.113 回答