祝各位新春快乐,身体健康,万事如意!
PS: 码年到了嘛,反正写码还是少不了的……
祝各位新春快乐,身体健康,万事如意!
PS: 码年到了嘛,反正写码还是少不了的……
这两天搞了一把DTrace,貌似还挺有意思的。
DTrace是个动态跟踪工具,可以在动态环境下向内核/程序中插入探头(probe),收集处理以及显示一些信息。
其实本来搞DTrace是为了一个FreeBSD的bug。搞chromecast的时候发现,IP multicast的目标mac不对。不过后来分析代码大致定位到了出问题的文件,然后在最新代码里发现这个bug已经修了(PR 185395),于是纯粹就是学习DTrace了。
一开始在我的机子上DTrace还跑不起来,后来发现是因为我跑的UEFI分支里的内核路径有些特别,于是DTrace找不到符号。打了个补丁(dt_kernel_path.patch)之后,dtrace终于能用了。
DTrace脚本的主体是一堆事件处理函数。跑DTrace脚本的时候,系统碰到某个符合的事件,就调用对应的函数。这些函数用D语言(不是那个D语言,是DTrace自己的一种语言)写成,语法和C差不多。基本的赋值/比较都能干,不过没有循环,也没有if/then/else。能控制流程的,基本上就是每个事件自带的条件,和三元操作符,也就是?:。
虽然前面那个bug是修了,我还是搞了个简单脚本来试DTrace。我希望观察arpresolve函数的参数和返回结果,也就是那个返回IP对应mac地址的函数。
arpresolve的原型是
int arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst, u_char *desten, struct llentry **lle) |
我希望查看dst里的ip地址,和desten里返回的mac地址。
DTrace脚本如下:
fbt::arpresolve:entry /execname == "ping" && arg4 != 0/ { ip = ((struct sockaddr_in *)arg3)->sin_addr.s_addr; a = (ip & 0xff000000) >> 24; b = (ip & 0xff0000) >> 16; c = (ip & 0xff00) >> 8; d = ip & 0xff; a4 = (unsigned char *)arg4; printf("%s %d.%d.%d.%d", execname, d, c, b, a); } fbt::arpresolve:return /execname == "ping" && a4 != 0/ { printf("%s %02x.%02x.%02x.%02x.%02x.%02x", execname, a4[0], a4[1], a4[2], a4[3], a4[4], a4[5]); } |
这里定义了俩probe,一个在arpresolve的入口(entry),还有一个在返回的时候触发。probe的名字有四个部分:
<provider>:<module>:<function>:<name>
provider就是提供这个probe的组件,例如fbt就是Function Boundary Tracing,其他还有syscall追踪system call的调用等。fbt可以追踪几乎内核里所有函数的调用……
module和function确定了包含这个probe的函数。module是模块名,function是函数名。如果一个部分为空(例如这里的module),那相当于*。
name就是这个特定probe的名字,这里entry和return都是。
第一个probe其实完整名字是fbt:kernel:arpresolve:entry,最简单弄成::arpresolve:entry也可以,反正没有别的。
每个probe还能限制触发条件,例如这里的execname == “ping” && arg4 != 0。这个稍微可以弥补一些没有if的缺陷。
在fbt的entry probe中,arg0, arg1…可以用来访问参数,而在return那里,arg0有返回地址(用以区分是哪个return返回的),arg1有返回值。
据说args[i]可以访问带类型的参数,但是我没试成…… 所以这里弄来arg3, arg4强转成了参数类型。DTrace会读取内核里的类型信息,所以各个数据类型直接就能用,这里就不用自己定义sockaddr_in了。转完之后,直接打出来就可以了。
因为在return那边没法读取参数,在entry里我先存了起来。
存了脚本,用dtrace -s就可以跑了。跑出来大概是这样:
> sudo dtrace -s arp.d
dtrace: script ‘arp.d’ matched 2 probes
CPU ID FUNCTION:NAME
1 20699 arpresolve:entry ping 239.255.255.250
1 20700 arpresolve:return ping 01.00.5e.7f.ff.fa
3 20699 arpresolve:entry ping 239.255.255.250
3 20700 arpresolve:return ping 01.00.5e.7f.ff.fa
1 20699 arpresolve:entry ping 239.255.255.250
1 20700 arpresolve:return ping 01.00.5e.7f.ff.fa
^C
当然这个是已经修完了的,修之前ip是网关的ip,mac变成了网关IP根据multicast对应规则转换成mac的结果,例如ip是192.168.1.1,mac是01.00.5e.28.01.01,总之很诡异…… 其实multicast情况下mac应该是用dest ip转的,那个修正也就是修了这个。
DTrace看上去挺有用的,对调试来说简直是静态调试的理想环境,插入调试语句都不用中断运行,也不用担心调试语句写错导致系统crash,还可以访问符号,大大加快调试速度。profiling应该也挺有用,不过我还没研究。
不过没有循环我倒是觉得可能会造成一些麻烦,例如在链表里找东西之类就不好找了。估计还是为了安全性验证和效率考虑吧,不过如果信得过的话,允许程序员用也未尝不可啊。
DTrace一开始是Solaris搞的,后来Mac和FreeBSD都port了一份过来。根据布总的教导,各个系统都有,windows下面有个可以处理SQL语句的,Linux虽然官方内核没有,但是有一堆第三方的。
祝各位新年快乐!
PS. 刚好新年的时候VPS居然坏了…… 还是搬到EC2去吧!
在这个White Album(虽然没有下雪……)的季节里,诸位圣诞快乐!
家里的台式机CPU温度过高已经很长一段时间了。一个i5-2500K的CPU,全功率运转的时候温度轻松上百,在BIOS里面看着温度监控都能到87,平时闲着也有七十几,这俨然不正常。
前两天拆开来,发现风扇里面好多灰…… 于是清理了一把。本来想着这回应该没问题了,结果开机之后状况依旧,丝毫没有好转……
拆开来的时候发现风扇底下的导热膏已经全干了,剩下一层灰状物质分布在散热片表面和CPU表面。之前听说过导热硅脂干了会影响散热,因为硅脂干了之后,CPU和散热片之间会有空气间隙,导热很差,于是CPU的热量无法传达到散热片上。这种情况需要换新的导热硅脂。虽然没搞过,还是可以一试。于是去Amazon上随便搞了个5刀的导热硅脂,搞败了也没啥损失。
今天硅脂送到了,拆开来之后看上去是个针筒,不过比较细,头上有个盖子。
拆下CPU上的风扇,把上面的旧硅脂车掉,再把CPU拆下来也这么搞一遍。全搞干净之后,我开始研究硅脂怎么涂……
网上说可以用玻璃棒啦针头啦之类的涂。拧开盖子之后,看上去就是个针筒头的样子。把针筒顶在散热片上轻轻按下去,出来了大约1mm粗细的牙膏样的东西。
反正我也没有别的工具,干脆直接用这个针筒的头来涂。重复着挤出来一些再抹到边上去的操作,直到看上去基本上都布满了……
看网上的说法应该均匀涂,还要啥薄的像纸但是没有空隙…… 想想反正装上去之后就会压平的,谁管那么多……
涂完之后把风扇装回去,因为装得不太顺利还抬起来了几次。装完之后,怀着忐忑不安的心情开机……
貌似效果还不错,BIOS里看看也就四十几,进了系统闲着也就四五十的样子。全功率跑起来,温度升…… 升…… 也就升到刚过七十。
现在跑了几个小时了,还是71~73的样子,系统温度35。看来基本上算是成功了。
之后再观察个几天,看看会不会有所反复。终于可以全功率跑程序了……