我说
我梦见自己的房间里漂浮着流动的音箱 音符 钟表 时间表 曲线报表 关系报表
每个上面都有你的映像
有我们关系冷暖的时间曲线
准确说 我梦见了我处在有你在的数字孪生空间
我正努力的寻找每个数字拐点的节点时间和事件
你回复了我一句: 甜吗
我以为说的是数字: 不甜
但我突然想到你问的可能是我处在这样空间的感觉 问的是有你印记同在时我的感觉
我说: 等等 很甜
我总觉得对你的爱很美
Memory Overcommit的意思是操作系统承诺给进程的内存大小超过了实际可用的内存.
一个保守的操作系统不会允许memory overcommit, 有多少就分配多少, 再申请就没有了, 这其实有些浪费内存, 因为进程实际使用到的内存往往比申请的内存要少
比如某个进程malloc()了200MB内存, 但实际上只用到了100MB, 按照UNIX/Linux的算法, 物理内存页的分配发生在使用的瞬间, 而不是在申请的瞬间, 也就是说未用到的100MB内存根本就没有分配, 这100MB内存就闲置了
下面这个概念很重要, 是理解memory overcommit的关键: *commit(或overcommit)针对的是内存申请, 内存申请不等于内存分配, 内存只在实际用到的时候才分配. *
不做任何优化, 这是默认的编译选项.
-O和-O1: 对程序做部分编译优化, 对于大函数,优化编译占用稍微多的时间和相当大的内存. 使用本项优化, 编译器会尝试减小生成代码的尺寸, 以及缩短执行时间, 但并不执行需要占用大量编译时间的优化.
fdefer-pop: 延迟栈的弹出时间. 当完成一个函数调用, 参数并不马上从栈中弹出, 而是在多个函数被调用后, 一次性弹出.
fmerge-constants: 尝试横跨编译单元合并同样的常量(string constants and floating point constants)
fthread-jumps: 如果某个跳转分支的目的地存在另一个条件比较,而且该条件比较包含在前一个比较语句之内,那么执行本项优化.根据条件是true或者false,前面那条分支重定向到第二条分支的目的地或者紧跟在第二条分支后面.
floop-optimize: 执行循环优化,将常量表达式从循环中移除, 简化判断循环的条件, 并且optionally do strength-reduction, 或者将循环打开等. 在大型复杂的循环中, 这种优化比较显著.
fif-conversion: 尝试将条件跳转转换为等价的无分支型式. 优化实现方式包括条件移动, min, max, 设置标志, 以及abs指令, 以及一些算术技巧等.
fif-conversion2基本意义相同, 没有找到更多的解释.
fdelayed-branch: 这种技术试图根据指令周期时间重新安排指令. 它还试图把尽可能多的指令移动到条件分支前, 以便最充分的利用处理器的治理缓存.
fguess-branch-probability: 当没有可用的profiling feedback或__builtin_expect时, 编译器采用随机模式猜测分支被执行的可能性, 并移动对应汇编代码的位置, 这有可能导致不同的编译器会编译出迥然不同的目标代码.
fcprop-registers: 因为在函数中把寄存器分配给变量, 所以编译器执行第二次检查以便减少调度依赖性(两个段要求使用相同的寄存器)并且删除不必要的寄存器复制操作.
1 | dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart |
下载wsl_update_x64.msi
WSL2 Linux kernel update package for x64 machines
1 | wsl --set-default-version 2 |
安装debian
microsoft store 选择Debian
1 | sudo passwd root |
1 | 1. Create file wsl.conf in /etc/ with content: |
1 | // windows下使用unix换行符 |
install “Remote - WSL”
install “Markdown All in One”
install “GitHub Theme”
设置选项搜索”eol” 设置为LF
设置选项搜索”font” 设置字体 Hack, Hack, Hack
CR(Carriage Return)代表回车(转义序列\r),将光标移动到当前行的开头。
LF(Line Feed)代表“换行”,但你可能更熟悉术语换行符(转义序列 \n)。 (unix)
CRLF (windows采用)
1 | * autocrlf: true |
find ./ -name *.h | xargs dos2unix
```
在计算机系统中,CPU高速缓存(英语:CPU Cache,在本文中简称缓存)是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。
当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据;如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。
缓存之所以有效,主要是因为程序运行时对内存的访问呈现局部性(Locality)特征。这种局部性既包括空间局部性(Spatial Locality),也包括时间局部性(Temporal Locality)。有效利用这种局部性,缓存可以达到极高的命中率。
在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。
本文阐述了GCC提供的内联汇编功能的使用和用法
本文主要为了阐述zperf性能分析器的核心编写逻辑.
在这篇文章中, 主要介绍的是(GCC)内联汇编函数的基本格式和用法, 这里先介绍两个基本概念.
在C++中, inline关键字首先是C++语言层面的修饰符, 如同static/ const等.
该关键字的作用是将函数声明为一个内联(inline)函数: inline关键字作为指示器传递给优化器”优先采用函数的内联替换而非进行函数调用“.
即内联函数原本的优化目的 不使用控制转移指令跳转到函数体, 而是直接拷贝函数体到发生调用的位置, 从而达到避免函数调用的开销以及传参和返回等开销.
这里容易产生混淆的地方在于, 该修饰符对于上述优化的指示并非强制, 并且编译器拥有对任何未标注inline的函数的使用内联替换的自由(在编译的优化原则内);
也因此在实际的实践中, inline关键字对于函数的含义也从’优先内联’实际变成了’容许多次定义’, 并且该inline关键字在语义上的实际变化也在C++17得到的标准化的定义和进一步的扩展, 并进一步扫清了”header only”支持的剩余障碍.
内联汇编提供了在C/C++代码中直接嵌入汇编代码的能力, 其中, ‘asm’关键字充当了汇编指令和’C/C++’代码之间的接口.
接口 | 计时精度 | 自身消耗 | 跨平台能力 | 综合稳定性 | 备注 |
---|---|---|---|---|---|
C库函数 time(NULL) WIN32 | 1s | 32ns | 高 | 高 | |
C库函数 time(NULL) linux | 1s | 35ns | 高 | 高 | |
C库函数 time(NULL) MAC | 1s | 155ns | 高 | 高 | |
C库函数 clock WIN32 | 1ms | 38ns | 高 | 差 | 测试精度误差100ms左右 |
C库函数 clock linux | 1us | 216ns | 高 | 差 | 测试精度误差100ms左右 |
C库函数 clock linux(Intel X5650) | 1us | 766ns | 高 | 差 | 测试精度误差100ms左右 |
C库函数 clock MAC | 1us | 476ns | 高 | 差 | 测试精度误差100ms左右 |
C++ chrono system_clock WIN32 | 100ns | 33ns | 高 | 中 | |
C++ chrono system_clock linux | 1ns | 50ns | 高 | 中 | |
C++ chrono steady_clock WIN32 | 100ns | 44ns | 高 | 中 | |
C++ chrono steady_clock linux | 1ns | 50ns | 高 | 中 | |
QueryPerformanceCounter | 1ns | 28ns | 无 | 高 | |
GetSystemTimeAsFileTime | 1us | 4~23ns | 无 | 中 | |
clock_gettime | 1ns | 50ns | 无 | 差 | 优先CLOCK_REALTIME选项 |
lfence;rdtsc WIN32 | 0.3ns | 13ns | 高 | 高 | 手写跨平台汇编 |
lfence;rdtsc linux | 0.3ns | 13ns | 高 | 高 | 手写跨平台汇编 |
mfence;rdtsc WIN32 | 0.3ns | 22ns | 高 | 高 | 手写跨平台汇编 |
mfence;rdtsc linux | 0.3ns | 22ns | 高 | 高 | 手写跨平台汇编 |
lock;rdtsc WIN32 | 0.3ns | 15ns | 高 | 高 | 手写跨平台汇编 |
lock;rdtsc linux | 0.3ns | 15ns | 高 | 高 | 手写跨平台汇编 |
rdtsc WIN32 | 0.3ns | 7ns | 高 | 高 | 手写跨平台汇编 |
rdtsc linux | 0.3ns | 7ns | 高 | 高 | 手写跨平台汇编 |
rdtscp | 0.3ns | 16ns | 高 | 差 | 双路X5650 2.58us~2.28s抖动 |
clock_gettime
rdtsc
rdtscp
load fence rdtsc
load&store fence rdtsc
__rdtsc (WIN32)
对比测试
寄存器操作 1个circle
L1 cache hit 3个circle (不考虑在流水线中等情况)
L2 cache hit 12个circle
L3 cache hit 38个circle
主内存 65ns
NUMA内存 相比主内存增加总线访问延迟 约40ns
三元赋值一般约8个circle (存在指令并行,预读等和其他周围代码一起统计会有推算上的偏差)
s64类型两次乘法一次除法计算一次三元赋值和若干普通赋值的cpu统计代码消耗约为3.71ns (大样本均摊)
s64类型两次乘法 一次三元赋值和若干普通赋值的cpu统计代码消耗约为2.93ns (大样本均摊)
4次加法赋值 1.59ns (大样本均摊)
小结
一般CPU主频是2.5~4Ghz之间(对本文来说为标频, 睿频无意义), 标频通常代表着高精度计数的极限(INTEL平台下和同时和ART硬件有关)
std::chrono的稳定性和精度均为良好 并且跨平台性最好(C++11标准)
rdtsc精度最高 速度最快 稳定性最好 但是需要确认CPU体系和版本保证可用(当前只针对INTEL/AMD上市年份在07/08年以后的新CPU)