Misc 你知道吗?
记录一些想到的问题
1. 程序语言
- C/C++什么时候在全局变量前加 static ? Rust呢?
参考这个帖子,static 限制了变量仅在本文件内可见。
Rust中可以用来表达 “全局” 的是 const
或 static
,其中每次访问 const 都是自动内联的,详见文档
struct Node {}
impl Drop for Node {
fn drop(&mut self) {
println!("drop")
}
}
const I: Node = Node {};
fn main() {
let x = I;
let mut y = I; // 不会有move的问题,因为这里又新建了一个实例,运行结束有两次drop
let local = Node{};
let a = local;
// let b = local; //打开注释会有问题,因为没有 Copy
}
static 则不同,static 变量只会有一个实例,且即使程序结束也不会调用 drop
- 以下代码在编译完成后,反复执行,全局变量的地址是否改变?
#include <iostream>
int global_var = 10;
int main() {
printf("addr of global_var %p\n", &global_var);
}
理论上编译成可执行文件后,global_var的地址不变,但现代操作系统往往有Address Space Layout Randomization (ASLR) 所以实际运行发现会变,setarch $(uname -m) -R ./a.out
手动关闭后地址就不会变。
2. 体系结构
- 当我们讨论CPU cache时,cache的地址是虚拟地址还是物理地址?
如果直接使用PA,则每次需要VA 到 PA 的转换,耗时。如果直接使用VA,则存在不同地址空间相同VA的问题。一般的解决办法(x86)是,Virtually Indexed Physically Tagged (VIPT)。因为cache都比较小,所以可以利用VA和PA中相同的低位去查询cache中内容,同时拿 VA 的VPN 去 TLB 查对应的 PPN,最后比较是否有某个 cache 位置的高位(tag) 和 转换后的地址相同,如果有则hit cache。 VIPT被应用在L1cache,L2/3 cache 使用PIPT。 参考
- 现代 x86_64 CPU的cache line是多少?
从物理的角度说,是64 byte,可以写代码验证,不断更新两个在同一个cache line的变量,耗时比变量间隔 64 byte 明显更长(因为 false sharing)。但是一些库(folly/crossbeam-rs)会在代码中设置 128 byte 对齐,而不是 64byte,因为L2 cache 有 prefetcher 可能一次取两个cache line,也会有影响 。
- DRAM是支持随机访问的,那么顺序访问是否和乱序访问速度相同?
不是,DRAM顺序访问是可能比乱序访问快的,因为DRAM中有自己的cache。且DRAM写会比读更慢。此外多线程读DRAM比单线程读DRAM耗时更少,比如读2G数据,两个线程分别读1G的耗时显著比一个线程读2G耗时少,因为平时说DRAM慢主要是latency大,多线程提高了throughput。(todo 之前是看了一篇paper有实验结果的,找不到了)
3. 网络
- 现在网站流量那么大,如果每次来数据包都中断一次,这样岂不是切换上下文很多次?
是的,所以Linux有NAPI (new API)机制,处理中断时会poll网卡,询问是否还有数据包要处理,这样可以减少中断次数,提高效率。