我想在ARM Cortex A8处理器上移植一小段代码.L1缓存和L2缓存都非常有限.我的程序中有3个数组.其中两个是按顺序访问的(大小>阵列A:6MB,阵列B:3MB),第三个阵列(大小>阵列C:3MB)的访问模式是不可预测的.虽然计算不是很严格,但是访问阵列C时存在巨大的缓存未命中.我认为一种解决方案是为阵列C分配更多的缓存(L2)空间,而对于阵列A和B则分配更少.但我不能找到任何方法来实现这一目标.我经历了ARM的预加载引擎但找不到任何有用的东西.
可以使用sched_setaffinity()调用将进程固定到一组特定的CPU内核.手册页说:
Restricting a process to run on a single CPU also avoids the
performance cost caused by the cache invalidation that occurs when a process
ceases to execute on one CPU and then recommences execution on a different
CPU.
Run Code Online (Sandbox Code Playgroud)
这几乎是一个显而易见的事情(或不是?).对我来说不那么明显的是 -
将LWP固定到特定CPU或SMP节点会降低缓存一致性总线流量吗?例如,由于进程正在运行固定,因此其他CPU不应修改其专用内存,因此只有属于同一SMP节点的CPU应保持高速缓存一致性.
我有这样的循环
start = __rdtsc();
unsigned long long count = 0;
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
count += tab[i][j];
stop = __rdtsc();
time = (stop - start) * 1/3;
Run Code Online (Sandbox Code Playgroud)
需要检查预取数据如何影响效率.如何在计算之前强制从内存中预取一些值到缓存中?
最新的英特尔XEON处理器拥有30MB的L3内存,足以容纳薄型1管理程序.
我有兴趣了解如何在CPU中保留这样的Hypervisor,即防止被刷新到RAM,或者至少在发送到内存/磁盘之前加密数据.
假设我们使用裸机运行,我们可以使用DRTM(延迟启动)来引导它,例如我们从不受信任的内存/磁盘加载,但是如果我们可以解密()用于解密的秘密,我们只能加载真实的操作系统.操作系统,在设置了适当的规则以确保发送到RAM的任何内容都已加密后进行.
ps我知道TXT的ACEA又称ACRAM(认证代码执行区域又称认证代码RAM)据说有这样的保证(即它限制在CPU缓存中)所以我想知道是否可以在此周围做一些技巧.
pps这似乎超出了目前的研究范围,所以我实际上并不确定答案是否可行.
我写了一个测试速度的程序memcpy().但是,如何分配内存会极大地影响速度.
#include<stdlib.h>
#include<stdio.h>
#include<sys/time.h>
void main(int argc, char *argv[]){
unsigned char * pbuff_1;
unsigned char * pbuff_2;
unsigned long iters = 1000*1000;
int type = atoi(argv[1]);
int buff_size = atoi(argv[2])*1024;
if(type == 1){
pbuff_1 = (void *)malloc(2*buff_size);
pbuff_2 = pbuff_1+buff_size;
}else{
pbuff_1 = (void *)malloc(buff_size);
pbuff_2 = (void *)malloc(buff_size);
}
for(int i = 0; i < iters; ++i){
memcpy(pbuff_2, pbuff_1, buff_size);
}
if(type == 1){
free(pbuff_1);
}else{
free(pbuff_1);
free(pbuff_2);
}
}
Run Code Online (Sandbox Code Playgroud)
操作系统是linux-2.6.35,编译器是GCC-4.4.5,选项"-std = c99 -O3".
在我的计算机上的结果(memcpy …
虽然之前已经提出了关于链表和数组的问题,但答案大多归结为我们大多数人在某些时候可能已经学到的东西:
现在像Bjarne Stroustrup这样受人尊敬的人认为,数组实际上总是优于链表,因为它们更好地利用了现代硬件中实现的缓存架构.他还指出,阵列的性能优势随着它们的大小而增加.
虽然我基本上理解他的论点并同意他,但我想知道当数组的大小远大于缓存大小时,这是否仍然是正确的.我会说,性能真的很重要.
总结一下:在大多数情况下,数组仍然比列表表现更好,即使它们的大小比缓存大小大得多,并且大部分操作都是插入或删除吗?如果是,如何解释?
我想知道链接列表与C中的连续数组相比有什么优缺点.因此,我读了一篇关于链表的维基百科文章. https://en.wikipedia.org/wiki/Linked_list#Disadvantages
根据这篇文章,缺点如下:
- 由于指针使用的存储空间,它们使用的内存多于数组.
- 必须从头开始按顺序读取链接列表中的节点,因为链接列表本质上是顺序访问.
在反向遍历方面,链表中出现了困难.例如,单个链表很难向后导航,而双链表更容易阅读,内存浪费在分配上.
节点存储不明确,大大增加了访问列表中各个元素所需的时间,尤其是CPU缓存.
我理解前3分,但我最后一点很难:
节点存储不明确,大大增加了访问列表中各个元素所需的时间,尤其是CPU缓存.
关于CPU Cache的文章没有提到任何关于非连续内存阵列的内容.据我所知,CPU缓存仅缓存经常使用的地址,总共10 ^ -6缓存未命中.
因此,我不明白为什么CPU缓存在非连续内存阵列方面的效率会降低.
Write-Combine缓冲区是如何物理连接的?我已经看到了说明许多变体的方框图:
它是依赖于微架构的吗?
我目前正在学习Linux下的各种分析和性能实用程序,特别是valgrind/cachegrind.
我有以下玩具程序:
#include <iostream>
#include <vector>
int
main() {
const unsigned int COUNT = 1000000;
std::vector<double> v;
for(int i=0;i<COUNT;i++) {
v.push_back(i);
}
double counter = 0;
for(int i=0;i<COUNT;i+=8) {
counter += v[i+0];
counter += v[i+1];
counter += v[i+2];
counter += v[i+3];
counter += v[i+4];
counter += v[i+5];
counter += v[i+6];
counter += v[i+7];
}
std::cout << counter << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
用这个程序编译g++ -O2 -g main.cpp并运行valgrind --tool=cachegrind ./a.out,然后cg_annotate cachegrind.out.31694 --auto=yes产生以下结果:
--------------------------------------------------------------------------------
-- Auto-annotated source: /home/andrej/Data/projects/pokusy/dod.cpp
-------------------------------------------------------------------------------- …Run Code Online (Sandbox Code Playgroud) 一个普遍的说法是,缓存中的字节存储可能导致内部读 - 修改 - 写周期,或者与存储完整寄存器相比会损害吞吐量或延迟.
但我从未见过任何例子.没有x86 CPU是这样的,我认为所有高性能CPU也可以直接修改缓存行中的任何字节.一些微控制器或低端CPU是否有不同之处,如果它们有缓存的话?
(我不计算字可寻址的机器,或者字节可寻址但没有字节加载/存储指令的Alpha.我说的是ISA本身支持的最窄的存储指令.)
在我的研究中回答现代x86硬件可以不将单个字节存储到内存中吗?,我发现Alpha AXP省略字节存储的原因假设它们被实现为真正的字节存储到缓存中,而不是包含字的RMW更新.(因此,它会使L1d缓存的ECC保护更加昂贵,因为它需要字节粒度而不是32位).
所有现代架构(早期Alpha除外)都可以对不可缓存的内存(而不是RMW周期)进行真正的字节加载/存储,这对于为具有相邻字节I/O寄存器的设备编写设备驱动程序是必需的.(例如,使用外部启用/禁用信号来指定更宽总线的哪些部分保存实际数据,例如此ColdFire CPU /微控制器上的2位TSIZ(传输大小),或者像PCI/PCIe单字节传输,或者像DDR一样SDRAM控制信号掩盖选定的字节.)
对于微控制器设计,可能需要在缓存中为字节存储执行RMW循环,即使它不是针对像Alpha这样的SMP服务器/工作站的高端超标量流水线设计?
我认为这种说法可能来自可以用字寻址的机器.或者来自未对齐的32位存储,需要在许多CPU上进行多次访问,并且人们错误地将其从一般存储到字节存储.
为了清楚起见,我希望到同一地址的字节存储循环将在每次迭代中以与字存储循环相同的周期运行.因此,对于填充阵列,32位存储可以比8位存储快4倍.(也许如果少了32位门店饱和的内存带宽,但8位店家没有.)但是,除非字节存储有一个额外的惩罚,你不会得到更超过4倍的速度差.(或者无论宽度是多少).
而我在谈论asm.一个好的编译器会自动向量化C中的字节或int存储循环,并使用更宽的存储或目标ISA上的最佳存储.
; x86-64 NASM syntax
mov rdi, rsp
; RDI holds at a 32-bit aligned address
mov ecx, 1000000000
.loop: ; do {
mov byte [rdi], al
mov byte [rdi+2], dl ; store two bytes in the same dword
; no pointer increment, this is the same 32-bit dword every time
dec ecx
jnz …Run Code Online (Sandbox Code Playgroud) cpu-cache ×10
performance ×5
arm ×2
c++ ×2
cpu ×2
linked-list ×2
x86 ×2
arrays ×1
c ×1
cachegrind ×1
caching ×1
gcc ×1
hypervisor ×1
intel ×1
linux ×1
low-level ×1
malloc ×1
memcpy ×1
optimization ×1
prefetch ×1
profiling ×1