编辑:为了参考目的(如果有人偶然发现这个问题),伊戈尔奥斯特罗夫斯基写了一篇关于缓存未命中的精彩帖子.它讨论了几个不同的问题并显示了示例数字. 结束编辑
我做了一些测试<long story goes here>,我想知道性能差异是否是由于内存缓存未命中.以下代码演示了该问题,并将其归结为关键时序部分.以下代码有几个循环,以随机顺序访问内存,然后按升序地址顺序访问内存.  
我在XP机器(使用VS2005:cl/O2编译)和Linux机器(gcc -Os)上运行它.两者产生了相似的时间 这些时间以毫秒为单位.我相信所有循环都在运行并且未被优化(否则它将"立即"运行).
*** Testing 20000 nodes Total Ordered Time: 888.822899 Total Random Time: 2155.846268
这些数字有意义吗?差异主要是由于L1缓存未命中还是还有其他事情发生?存在20,000 ^ 2个存储器访问,并且如果每个都是高速缓存未命中,则每个未命中约3.2纳秒.我测试的XP(P4)机器是3.2GHz,我怀疑(但不知道)有一个32KB的L1缓存和512KB的L2.有20,000个条目(80KB),我假设没有大量的L2未命中.所以这就是(3.2*10^9 cycles/second) * 3.2*10^-9 seconds/miss) = 10.1 cycles/miss.这对我来说似乎很高兴.也许不是,或者我的数学很糟糕.我尝试用VTune测量缓存未命中,但我得到了BSOD.现在我无法连接到许可证服务器(grrrr).  
typedef struct stItem
{
   long     lData;
   //char     acPad[20];
} LIST_NODE;
#if defined( WIN32 )
void StartTimer( LONGLONG *pt1 )
{
   QueryPerformanceCounter( (LARGE_INTEGER*)pt1 );
}
void StopTimer( LONGLONG t1, double *pdMS )
{
   LONGLONG t2, llFreq;
   QueryPerformanceCounter( (LARGE_INTEGER*)&t2 );
   QueryPerformanceFrequency( (LARGE_INTEGER*)&llFreq );
   *pdMS …什么是CUDA全局内存事务中的"合并"?经过我的CUDA指南后,我无法理解.怎么做?在CUDA编程指南矩阵示例中,逐行访问矩阵称为"coalesced"或col .. by col ..称为合并?哪个是正确的,为什么?
通过指针进行内存访问比通过数组进行内存访问更有效.我正在学习C,上面的内容在K&R中有说明.他们特别说
通过数组下标可以实现的任何操作也可以使用指针来完成.指针版本通常会更快
我使用visual C++解组了以下代码.(我是一个686处理器.我已禁用所有优化.)
int a[10], *p = a, temp;
void foo()
{
    temp = a[0];
    temp = *p;
}
令我惊讶的是,我看到通过指针的内存访问需要通过数组对内存访问所采用的两条指令.以下是相应的代码.
; 5    : temp = a[0];
    mov eax, DWORD PTR _a
    mov DWORD PTR _temp, eax
; 6    : temp = *p;
    mov eax, DWORD PTR _p
    mov ecx, DWORD PTR [eax]
    mov DWORD PTR _temp, ecx
请帮我理解.我在这里失踪了什么?
正如许多答案和评论所指出的那样,我使用了编译时常量作为数组索引,从而使得通过数组访问变得更容易.下面是汇编代码,其中变量作为索引.我现在有相同数量的指令通过指针和数组进行访问.我更广泛的问题仍然很好.通过指针进行内存访问并不会使其本身更有效.
; 7    :        temp = a[i];
    mov eax, DWORD PTR _i
    mov ecx, DWORD PTR _a[eax*4]
    mov DWORD PTR _temp, …晚上好,
我一直在尝试构建一个golang应用程序,它扫描内存中的值,但我正在努力了解如何解决特定的内存位置.我知道当访问应用程序中的内存时,您可以使用*variablenamedeference并获取地址位置,但是我如何提供地址位置并将值打印到屏幕或从RAM中获取任何大小的下一个分配对象并打印它的值?
提前感谢您愿意分享的任何帮助
x86/x86_64体系结构的每个现代高性能CPU都有一些数据缓存层次结构:L1,L2,有时是L3(在极少数情况下是L4),从/向主RAM加载的数据缓存在其中一些中.
有时程序员可能希望某些数据不会缓存在某些或所有缓存级别中(例如,当想要memset 16 GB的RAM并将某些数据保留在缓存中时):有一些非时间(NT)指令用于这就像MOVNTDQA(/sf/answers/2596471/ http://lwn.net/Articles/255364/)
但有没有一种编程方式(对于某些AMD或Intel CPU系列,如P3,P4,Core,Core i*,......)完全(但暂时)关闭部分或全部级别的缓存,以改变每个内存的方式访问指令(全局或某些应用程序/ RAM区域)使用内存层次结构?例如:关闭L1,关闭L1和L2?或更改每次存储器访问类型CR0 ??? SDM vol3a页的"未缓存的" UC(CD + NW位423 424,425和" 仅适用于基于处理器的三级缓存禁止标志,位在IA32_MISC_ENABLE MSR 6(可用英特尔NetBurst微体系结构) - 允许禁用和启用L3缓存,独立于L1和L2缓存.").
我认为这样的行动将有助于保护数据免受缓存侧通道攻击/泄漏,如窃取AES密钥,隐蔽缓存通道,Meltdown/Spectre.虽然这种禁用会产生巨大的性能成本.
PS:我记得多年前在一些技术新闻网站上发布的这样一个程序,但现在找不到它.将一些神奇的值写入MSR只是一个Windows exe,并使每个Windows程序运行得很慢.缓存关闭直到重新启动或直到使用"撤消"选项启动程序.
API声明:
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" ( _
                         ByVal lpPrevWndFunc As Long, _
                         ByVal HWnd As Long, _
                         ByVal msg As Long, _
                         ByVal wParam As Long, _
                         ByVal lParam As Long) As Long
为lpPrevWndFunc参数提供不存在的函数指针时,Excel将崩溃。
同样,
Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As LongPtr, _
                                                  ByRef Source As LongPtr, _
                                                  ByVal Length As Long)
当Destination或Source不存在时不高兴。
我认为这些错误是内存访问冲突。我假设Windows告诉调用者它正在做某件事,而它做不到1-也许它向Excel发送了一条消息,并且没有处理程序?MSDN对此有以下说法:
调用Windows动态链接库(DLL)或Macintosh代码资源期间的系统错误不会引发异常,也无法使用Visual Basic错误捕获来捕获。调用DLL函数时,应检查每个返回值是否成功(根据API规范),如果失败,请检查Err对象的LastDLLError属性中的值。在Macintosh上,LastDLLError始终返回零。 (强调我自己)
但是在这些情况下,我没有任何值可以检查错误,只是崩溃了。
1:如果它捕获的错误不是经常发生的,例如说内存重写有效但未定义,则错误可能会一直存在。但是可以肯定的是,在执行限制之前,应该捕获对受限内存的写入或调用伪指针吗?
导致此崩溃的原因是什么(这是 …
编辑:在问题的最后添加建议的解决方案结果.
我开始用OpenCL编程,我已经创建了一个天真的问题实现.
理论是:我有一个3D网格元素,每个元素都有一堆信息(大约200字节).每一步,每个元素都访问其邻居信息并累积此信息以准备更新自身.之后,有一个步骤,每个元素使用之前收集的信息更新自己.该过程迭代执行.
我的OpenCL实现为:I 1种创建尺寸的OpenCL的缓冲液,与代表元素,至极结构填充它有一个"INT邻居[6]",其中我存储在缓冲器中的邻居的索引.我启动了一个内核,它咨询邻居并将他们的信息累积到这个步骤中没有参考的元素变量中,然后我启动另一个使用这个变量来更新元素的内核.这些内核仅使用__global变量.
示例代码:
typedef struct{
  float4 var1;
  float4 var2;
  float4 nextStepVar1;
  int neighbors[8];
  int var3;
  int nextStepVar2;
  bool var4;
} Element;
__kernel void step1(__global Element *elements, int nelements){
  int id = get_global_id(0);
  if (id >= nelements){
    return;
  }
  Element elem = elements[id];
  for (int i=0; i < 6; ++i){
    if (elem.neighbors[i] != -1){
      //Gather information of the neighbor and accumulate it in elem.nextStepVars
    }
  }
  elements[id] = elem;
}
__kernel void step2(__global Element *elements, int nelements){ …In order to find avg memory access time we have the formula :
Tavg = h*Tc +(1-h)*M
where  h     = hit rate
       (1-h) = miss rate
       Tc    = time to access information from cache
       M     = miss penalty  (time to access main memory)
我最近一直在解决这个概念上的一些问题.有时我发现存在这种令人不安的不一致:
Case 1: M = Tm + Tc
Case 2: M = Tm
意思是,解决方案表明,对于某些问题X计算"M"的值,如上面的"情况1",而在某些其他问题Y中,计算与上述"情况2"相同的值.我尽力分析这些问题,以找出使计算不同的因素.没有帮助.我遇到过X和Y完全相同的情况,只是值只是不同,但是对于X进行计算,如情况1和Y进行情况2.
我不知道的任何其他原因导致计算不同?先感谢您.
我在C#中使用的插件中有两个不同的功能.最近(显然)Solidworks在到达这两个函数的某些部分时可能会崩溃(可能更多,但是到目前为止我发现它只有两个.)在调试下,这两个函数都给我一个"内存访问违规"错误".每次在关闭活动文档的行上都会发生此错误,大约95%的时间都会发生此错误.
它几乎总是在同一个部分.它似乎与运行时间或已打开和关闭的部件数量无关.如果我不关闭文件,我似乎没有得到错误.但是在运行大型装配时,会出现问题.在关闭之前添加1s等待似乎可以减少错误的频率(因为,我可以偶尔通过整个程序集而没有错误)
快速解释我主要关注的功能是什么; 它从组件的顶层开始工作,将自定义属性从主组件和子组件传播到它们的子组件中.所以我不断打开和关闭不同的装配和零件文件.
下面的代码已被删除,几乎是复制错误的最低限度.错误发生在第59行.从目前为止我在网上看到的,似乎这些很难追查.任何帮助是极大的赞赏.
    public void propagateProps(bool overwrite)  
    {  
        List<string> assemblies = new List<string>();  
        string topAssem;  
        string compName = "";  
        int i = 0;  
        int j = 0;  
        int errors = 0, warnings = 0;  
        int partType = 1;  
        swModel = iSwApp.ActiveDoc;  
        if (swModel == null)  
        {  
            MessageBox.Show("No assembly document open. Please open an assembly and try again.", "Avengers Assemble Error");  
            return;  
        }  
        if (swModel.GetType() != 2)  
        {  
            MessageBox.Show("No assembly document open. Please open an assembly and try again.", …我最近被问到一段代码来"就地"对数组进行抽取/下采样.这个"抽取"函数采用一个int数组,并在索引i处的数组中的偶数索引处存储一个条目i/2.它为数组中的所有条目执行此操作.
这会将原始数组中所有偶数索引条目移动到数组的前半部分.然后阵列的其余部分可被初始化为0总的结果是,保留了原始阵列中的所有偶数索引条目(通过将它们移动到第一半部分)的阵列,并且所述阵列的第二半被0.这显然用于在信号处理中对信号进行下采样.
代码看起来像这样:
void decimate (vector<int>& a) {
   int sz = a.size();
   for (int i =0; i < sz; i++) {
     if (i%2 == 0) {
        a[i/2] = a[i];
     }
    }
    for (int i =(sz-1)/2; i < sz; i++) a[i] = 0;
}
在建议将某些变量保留在寄存器中的基本改进之后,我找不到任何进一步优化它的方法,但不确定是否无法完成.
有没有办法可以优化循环中的内存访问模式,以获得更好的缓存性能? 或者任何其他方法来优化将阵列压缩/下采样到上半部分的主要复制操作?(例如,通过支持它的平台进行矢量化)
   for (int i =0; i < sz; i++) {
     if (i%2 == 0) {
        a[i/2] = a[i];
     }
    }
是否有任何循环变换(例如平铺/条带挖掘)可以为这种抽取循环带来高效的代码?
编辑:在下面的答案中提出了几种不同的方法,似乎利用memset/fill或指针算法来提高速度效率.这个问题主要集中在是否有明确定义的循环变换可以显着改善局部性或缓存未命中(例如,如果它是一个带有两个循环的循环嵌套,可能会考虑循环平铺以优化缓存未命中)
memory-access ×10
c ×2
caching ×2
performance ×2
arrays ×1
c# ×1
c++ ×1
cpu-cache ×1
cuda ×1
definition ×1
excel ×1
go ×1
gpgpu ×1
intel ×1
loops ×1
memory ×1
msr ×1
opencl ×1
optimization ×1
pointers ×1
solidworks ×1
vba ×1
winapi ×1
x86 ×1