![e4e3e3f5603e154bf91d568de5ea2241.png](https://i-blog.csdnimg.cn/blog_migrate/a12822a215f08f2391bf558842370aea.jpeg)
效果如下:
![7a764d7101f045c12d34ffa86eeac564.png](https://i-blog.csdnimg.cn/blog_migrate/7610d8fe5c740dd5f886f5e769bd45e2.jpeg)
此例展示的是linux最常用的系统调用 - open()的函数调用树
-----
推荐 linux C函数流程图 以及linux文件树
老白Walt:[R+bash] 5分钟内制作一张linux C函数流程图 - DiagrammeR
老白Walt:[R] 展示linux文件树 - collapsibleTree
1 获取数据
1.1 函数调用栈
cflow - 一款生成函数调用栈的命令行工具
举个例子:
![a3ccaf632b68009c6e5e02a78930a9b2.png](https://i-blog.csdnimg.cn/blog_migrate/eb3a856d3d471f40614ad852a56a70e9.jpeg)
用法就是这样子:
cflow -m 函数名 文件名
直接输出调用栈,以缩进表示stack depth,赞!不过如果我将include/, block/, mm/目录的文件都加进来的话,这个stack会非常非常长,在shell下看会崩溃,因此这里要发挥R语言的优势啦
不过在进入R之前还有一个问题: 这个数据格式R语言可没有东东认得!经过一番搜寻发现一条可行的数据转换的path:
[shell] cflow -> grep/perl/sed -> .yaml -> [R] -> yaml::yaml.load_file -> data.tree::as.Node
最终可以转换为Node格式,就可以优雅地用collapsibleTree来展示了
而连接shell和R的东东就是YAML
注:cflow是有BUG的,并不是总能很好的解析函数,所以不能过度依赖
1.2 YAML
下面就是YAML的一种格式
a_nested_map:
key: value
another_key: Another Value
another_nested_map:
hello: hello
key: value而value也可以是多个key: value对
cflow的输出正好有缩进,我只需要把key: value给转换好即可
1.3 cflow -> YAML
find fs/*.* fs/notify include/linux/ -name '*.[ch]' | grep -Pv 'w*(?:pr_|print|trace|lock)' | xargs cflow -m vfs_open 2> /dev/null | sed -r '/^s*(pr_[^(]+|printk|ssize_t|loff_t)()/d' | perl -pe 's/^(s*)([^(]+)()(?:$|s+<.* at ([^>]+)>.*$)/12:n1 file: 3/' > open.yaml
find fs/*.* fs/sysfs fs/notify include/linux/ -name '*.[ch]' | grep -Pv 'w*(?:pr_|print|trace|lock)'
用find找fs和include下的.c和.h,再用grep过滤掉一些debug的文件
open()函数定义在fs/open.c:
![d48a8db65d59b2e9ddcbcbe55e69d7f0.png](https://i-blog.csdnimg.cn/blog_migrate/ddd70d8a20f4b0c482e406597681347a.png)
不过因其定义是宏展开的,cflow还没有强大到可以捕获,因此这里跳到vfs_open()代替;另外静态工具对函数指针无计可施,因此调用栈还无法深入到具体的文件系统
xargs cflow -m vfs_open 2> /dev/null
用cflow -m vfs_open生成调用栈
![63403a00159cc392a48f4d54699409ce.png](https://i-blog.csdnimg.cn/blog_migrate/393cdc293ca3e63a93f9a8782e940945.png)
perl -pe 's/^(s*)([^(]+)()(?:$|s+<.* at ([^>]+)>.*$)/12:n1 file: 3/' > open.yaml
最后用perl将文本转换为YAML格式:
![956861260d38057968a5004caff2c753.png](https://i-blog.csdnimg.cn/blog_migrate/97fa844f092d0fa3b7855855a6657bdb.jpeg)
至此,shell处理部分结束
2 R数据处理
2.1 加载YAML
![0fa3cbb231340b0aacc408bf01219ac4.png](https://i-blog.csdnimg.cn/blog_migrate/0c42f95ab43f63eb4be335bd59953a92.jpeg)
yaml::yaml.load_file('d:/linux-master/open.yaml')
yaml包的yaml.load_file会将文件转为list
2.2 YAML -> data.tree::Node
![0d89a681848edb1deb1f83410203fed1.png](https://i-blog.csdnimg.cn/blog_migrate/680663e77f1c1a35d3b22847c693d83b.jpeg)
data.tree::as.Node(ylst)
data.tree包的as.Node方法会将其转为Node class,它的功能是十分丰富的,有兴趣的可以移步到下面链接:
https://cran.r-project.org/web/packages/data.tree/vignettes/data.tree.htmlcran.r-project.org3 绘图
yaml::yaml.load_file('d:/linux-master/open.yaml') %>%
data.tree::as.Node() %>%
collapsibleTree::collapsibleTree(
fill = 'orangered',
root = 'vfs_open',
width = 1850,
height = 900,
attribute = 'file',
tooltip = T
)
![85a774991ae156f5dd35b6009a198c2c.png](https://i-blog.csdnimg.cn/blog_migrate/113499e297ab498f53413a67f7d8840b.jpeg)
可喜的是鼠标移动到节点上,可以显示函数定义所在的文件和行数
啃linux源码终于不用在纸上画了
本专栏只生产干货,喜欢请关注:
数据及可视化zhuanlan.zhihu.com![674095e66151bf2a9ff2308e688fb286.png](https://i-blog.csdnimg.cn/blog_migrate/2b29c31ce0ff7f3844073fc243572e6b.jpeg)