8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
说明
介绍systemtap, stap++的一些使用方式,以及总结了一些遇到的坑点
systemtap介绍
systemtap跟perf一样也是一个linux下的性能分析工具,但它提供自定义脚本编写,所以功能会比perf更强大。
快速了解systemptab功能
最简单的systemtab脚本1
2
3
4
5probe begin
{
print("hello worldn")
exit()
}
执行结果
1
2[email protected]:~/systab$ sudo stap hello-world.stp
hello world
probe begin指定了一个begin的追踪点,脚本实际上做的就是定义一些列追踪点。systemtap将脚本翻译成C,并将其编译成一个内核的模块加载到内核。一旦被加载则脚本中所有指定的追踪点会在运行的时候被回调。下面列举了一些systemtap提供的追踪点:begin:此次检测开始被回调
end: 此次检测结束被回调
kernel.function(“sys_open”): 内核函数sys_open进入时候被回调
syscall.close.return: 系统调用close返回时候被回调
timer.ms(200): 定时器,每200ms回调一次
timer.profile: 定时器,每个system tick回调一次
perf.hw.cache_misses: cache miss的时候回调
另一个例子1
2
3
4
5
6
7
8probe syscall.open
{
printf("%s"(%d) open (%s)n", execname(), pid(), argstr)
}
probe time.ms(4000)
{
exit()
}
执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24[email protected]:~/systab$ vi strace-open.stp
[email protected]:~/systab$ sudo stap ./strace-open.stp
redis-server(24453) open ("/proc/24453/stat", O_RDONLY)
bot(28026) open ("/proc/self/stat", O_RDONLY)
bot(28026) open ("/proc/stat", O_RDONLY)
redis-server(24453) open ("/proc/24453/stat", O_RDONLY)
redis-server(24453) open ("/proc/24453/stat", O_RDONLY)
tail(3649) open ("logs/zqc/gameapp.3.INFO", O_RDONLY|O_NONBLOCK)
tail(3651) open ("logs/zqc/gameapp.5.INFO", O_RDONLY|O_NONBLOCK)
mgrapp(3845) open ("/proc/self/stat", O_RDONLY)
mgrapp(3845) open ("/proc/stat", O_RDONLY)
tail(3652) open ("logs/zqc/gateapp.2.INFO", O_RDONLY|O_NONBLOCK)
tail(3650) open ("logs/zqc/gameapp.4.INFO", O_RDONLY|O_NONBLOCK)
mgrapp(11899) open ("/proc/self/stat", O_RDONLY)
mgrapp(11899) open ("/proc/stat", O_RDONLY)
gateapp(3849) open ("/proc/self/stat", O_RDONLY)
gateapp(3849) open ("/proc/stat", O_RDONLY)
gateapp(11903) open ("/proc/self/stat", O_RDONLY)
gateapp(11903) open ("/proc/stat", O_RDONLY)
loginapp(3847) open ("/proc/self/stat", O_RDONLY)
loginapp(3847) open ("/proc/stat", O_RDONLY)
redis-server(24453) open ("/proc/24453/stat", O_RDONLY)
gameapp(3855) open ("/proc/self/stat", O_RDONLY)
...
printf是一个格式化打印函数,可以打印自己脚本定义的变量,或者systemtap提供的获取信息的函数或变量:tid(): 当前线程id
pid(): 当前进程id
uid(): 当前用户id
execname(): 进程的名字
cpu(): 当前cpu number
gettimeofday_s(): 当前时间戳
pp(): 描述当前追踪点的字符串
ppfunc(): 当前追踪点被触发的函数,如果存在的话
print_backtrace(): 直接输出内核态堆栈
print_ubacktrace(): 直接输出用户态堆栈
systemtap脚本语法
普通语法和C语言差不多,这里介绍下不太一样的地方,其他具体可以查看官方教程,或者这个简化版的教程
数组
数组非常方便,内部使用hash table实现,数组大小除非显示指定,否则都定义为一个预先定义好的大小。多维可以直接用’,’分割即可,例如:
1
2
3
4
5
6
7
8
9
10
11names[400] // 大小位400的数组
...
foreach (name in names) {
// do something
}
foo[1, "200"] = 1
foo[2, "200"] = 2
foreach ([id, str] in foo) {
// do something
}
这里有个方便的地方当数组元素不存在的时候返回的是0,所以计数的时候就非常方便,可以直接使用bts[ubacktrace()]++计数
stap++介绍
stap++是一个stap扩展,提供一些类似于宏的功能,最后将宏替换后生成的systemtap脚本,并调用systemtap执行。
stap++使得systemtap的脚本可以得到进一步扩展。
sample-bt.sxx(perf record)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#!/usr/bin/env stap++
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
global bts;
global quit = 0
probe timer.profile {
if ($^pid_ok) { // pid是否相等
%( "$^arg_execname :default()" != "" %?
if (execname() == "$^arg_execname") { // 进程名是否相等,如果存在的话
%)
if (!quit) {
bts[ubacktrace()] <<< 1 // 计数,这里有个大坑,如果采样时间长会导致消耗巨量内存,可以改用bts[ubacktrace()]++优化
} else {
foreach (usr in bts- limit $^arg_limit :default(1000)) {
print_ustack(usr)
printf("t%dn", @count(bts[usr])) // 打印堆栈和数量,如果上面改为bts[ubacktrace()]++,这里可以直接输出bts[usr]的值
}
exit()
}
%( "$^arg_execname :default()" != "" %?
}
%)
}
}
probe timer.s($^arg_time) {
nstacks = 0
foreach (bt in bts limit 1) {
nstacks++
}
if (nstacks == 0) {
warn("No backtraces found. Quitting now...n")
exit()
} else {
warn("Time's up. Quitting now...(it may take a while)n")
quit = 1
}
}
probe begin {
warn(sprintf("Start tracing process $^target ($^exec_path)...n"))
}
这脚本实现了perf record功能,统计了每次采样的堆栈。
命令执行方式,其中PID是需要进行采样的进程id
1sudo ./stap++ samples/sample-bt.sxx -x PID -D MAXMAPENTRIES=102400 -D MAXBACKTRACE=100 -D MAXSTRINGLEN=4096 -D MAXACTION=100000 -D STP_OVERLOAD_THRESHOLD=5000000000 -D MAXSKIPPED=100000 --arg time=60 > ~/cpp.bt
采样之后可以使用命令cat ~/cpp.bt|c++filt|~/FlameGraph/stackcollapse-stap.pl|~/sysperf/FlameGraph/flamegraph.pl > ~/cpp.svg生成火焰图