You are your tools -- Daniel Lemire
拯救程序员无数次的自动化工具
熟悉项目
make -n -j$(nproc) > make_log
%!grep -ve '^\(\#\|echo\|mkdir\|make\)' # 过滤掉无用信息
%s/ /\r /g # 将空格替换为换行符
%!grep -vE '^ -[^co].*$' # 删除模式为所有"^ *$"的行删除掉,保留"^ [co]$"
%s/\v( \n){3,}//g # 删除模式为至少出现三次“空格后跟换行符”的行
香山处理器项目的基础设施
2021年RISC-V中国峰会, 工具类报告占香山团队报告总量55%(12/22)

效率的实际体现


最小化的linux
$ tree minimal-linux
.
├── initramfs
│ ├── bin
│ │ └── busybox
│ └── init
├── Makefile
└── vmlinuz
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
The following packages have unmet dependencies:
package1 : Depends: package2 (>= 1.8) but 1.7.5-1ubuntu1 is to be installed
E: Unable to correct problems, you have held broken packages.
Core advantage
Shell 是一门 “把用户指令翻译成系统调用” 的编程语言

基于文本替换的快速工作流搭建
cmd > file < file 2> /dev/nullcmd1; cmd2, cmd1 && cmd2, cmd1 || cmd2cmd1 | cmd2$(), <()Job control
有什么好处? 这些在GUI下点点鼠标也能做
1、 比较两个文件是否完全相同
CLI下的解决方案
vimdiff file1 file2diff file1 file2md5sum file1 file2一次也省不了多少时间 😕
2、查笔记
doc
3、CPU主频监视器
watch -t -n 1 "cat /proc/cpuinfo | grep MHz | awk '{print \$1 NR \$3 \$4 \$2}'"
有些稍微复杂的事GUI几乎做不了
例子: 列出一个C语言项目中所有被包含过的头文件
CLI的解决方案:
find . -name "*.[ch]" | xargs cat | grep "^#include" | sort | uniq
体现出的Unix philosophy
自动化脚本

使用工具 = 编程
Unix is user-friendly
++--------------------------------------------------------------+
|+--------------------------------------------------+ |
||+---------------------------------+ | |
|||+----------------+ | | |
|||| | | | |
vvvv |N Y |N Y |N Y |
读代码 => 写代码 => 写完? --> 编译 => 正确? --> 运行 => 正确? --> 下一个功能
更现代的CLI工具
Compilation & Assembly
bear -- make -j$(nproc)
without ccache 2:14.76 total
with ccache first time 2:42.42 total
make clean && with ccache second time 40.062 total
学习成本:30s(STFW: improving build speed on Linux) + 30s(RTFM: configure ccache)
Linking
# Just modified several compilation unit
bear -- make -j$(nproc)
without cache 10.271 total
with ccache 9.987 total
可以更快吗?(STFW: make linker faster)
with mold 1.433 total
脑科学研究表明: 人脑的短期记忆容量是有限的(7±2个单元)
扩大可持续工作时间的比例
# gdb 窗口切换快捷键
$if gdb
"\C-j":"focus next\r"
"\C-k":"focus prev\r"
$endif
# 按下CTRL-O,在光标后面添加 "> output.txt"
Control-o: "> output.txt"
一个重要的踪迹工具: strace
打开黑盒的方法
例1:"ls"命令是如何被找到的
strace -f bash -c "ls" 2>&1 | nvim - # -f 跟踪子进程
例2:用户如何与man交互
strace -o strace.log -f man ls # -o 将跟踪结果重定向到指定文件中
tail -f strace.log # 持续输出追加的数据
fineperf:解决perf难以profile指定代码段的问题
#include "perf.hpp"
// ...
perf_[stat|record]("/path/to/output",[&]() {
// code needed be profiled
});
// ...
从编译、操作系统、处理器的角度去理解程序的构建和执行过程
|
从源码构建Nixos/Archlinux软件包(例如使用wine)-> 了解elf、程序的加载 -> 更清晰理解elf相关问题
# diff sections_with_debug secitons_without_debug
< 27 .debug_aranges 00000030 0000000000000000 0000000000000000 0000303b 2**0
< CONTENTS, READONLY, DEBUGGING, OCTETS
< 28 .debug_info 0000031b 0000000000000000 0000000000000000 0000306b 2**0
< CONTENTS, READONLY, DEBUGGING, OCTETS
< 29 .debug_abbrev 000000e2 0000000000000000 0000000000000000 00003386 2**0
< CONTENTS, READONLY, DEBUGGING, OCTETS
< 30 .debug_line 00000113 0000000000000000 0000000000000000 00003468 2**0
< CONTENTS, READONLY, DEBUGGING, OCTETS
< 31 .debug_str 00000292 0000000000000000 0000000000000000 0000357b 2**0
< CONTENTS, READONLY, DEBUGGING, OCTETS
Initial log
2 0x55dce756509c postgres: 6000, logger process <symbol not found> + 0xe756509c
3 0x7f4ddfeb2420 libpthread.so.0 <symbol not found> + 0xdfeb2420
4 0x55dce7217556 postgres: 6000, logger process <symbol not found> + 0xe7217556
5 0x55dce7218106 postgres: 6000, logger process <symbol not found> + 0xe7218106
6 0x55dce721b251 postgres: 6000, logger process <symbol not found> + 0xe721b251
. . .
15 0x55dce71f4ef4 postgres: 6000, logger process <symbol not found> + 0xe71f4ef4
16 0x55dce71f9b7b postgres: 6000, logger process <symbol not found> + 0xe71f9b7b
17 0x55dce71f6b12 postgres: 6000, logger process standard_ExecutorRun + 0x3d5
18 0x55dce71f673a postgres: 6000, logger process ExecutorRun + 0x5d
19 0x55dce756ae30 postgres: 6000, logger process <symbol not found> + 0xe756ae30
20 0x55dce756a9fb postgres: 6000, logger process PortalRun + 0x2c7
21 0x55dce75611bc postgres: 6000, logger process <symbol not found> + 0xe75611bc
22 0x55dce7567e8c postgres: 6000, logger process PostgresMain + 0x1433
Enhanced log
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(tuplestore_gettupleslot+0x43) [0x55ebe93a5813]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecMaterial+0x320) [0x55ebe8e2a8fe]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecProcNodeGPDB+0x129) [0x55ebe8df38b6]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecProcNode+0x36) [0x55ebe8e35be8]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecNestLoop_guts+0x508) [0x55ebe8e362b4]
. . .
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecProcNode+0x36) [0x55ebe8de4f14]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecutePlan+0x108) [0x55ebe8de9b9b]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(standard_ExecutorRun+0x3d5) [0x55ebe8de6b32]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(ExecutorRun+0x5d) [0x55ebe8de675a]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(PortalRunSelect+0x120) [0x55ebe915ae50]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(PortalRun+0x2c7) [0x55ebe915aa1b]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(exec_mpp_query+0xadf) [0x55ebe91511dc]
/home/gpadmin/piemaster/piedb_cluster/bin/postgres(PostgresMain+0x1433) [0x55ebe9157eac]
过程
-> 找出打印调用栈的函数:backtrace_symbols
-> glibc没有调试信息,不能跟踪 😒
-> 编译glibc,跟踪backtrace_symbols
-> 只在.dynsym section中寻找Bind类型为GLOBAL和WEAK的符号
-> 加载.symtab section,找到pdb中大量Bind类型为LOCAL的static函数的符号
搭建Lfs、Gentoo可能需要裁剪内核 -> 了解到运行内核的方式 -> 修改内核的信号处理机制方便调试程序
/* include/linux/signal.h */
// 1: coredump
#define SIG_KERNEL_ONLY_MASK (\
rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP))
#define SIG_KERNEL_COREDUMP_MASK (\
rt_sigmask(SIGQUIT) | rt_sigmask(SIGILL) | \
...)
// 2: handler
/* Invert the set of allowed signals to get those we want to block. */
sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
|
学习成本
减轻对“黑魔法”的困惑
#include <iostream>
int main()
{
while (1) ;
}
void mayreachable()
{
std::cout << "Hello world!" << std::endl;
}
|
尝试解开“黑魔法”
验证:添加编译选项"-trap-unreachable" 😀

