![8cc14337c8bdb0b134d7492a16cef64c.png](https://i-blog.csdnimg.cn/blog_migrate/64b3734afeb413ae5b23801126d50337.png)
grViz制作过程如下:
![181e758af627a15a3255fb16ad24e470.png](https://i-blog.csdnimg.cn/blog_migrate/a73b2e51a9a5e8210a654bcf10601a0a.jpeg)
-----
推荐专栏另外两篇相关文章: linux C函数调用栈 以及 linux文件树
老白Walt:[R] 如何用树展示linux C函数调用栈 - collapsibleTree
老白Walt:[R] 展示linux文件树 - collapsibleTree
1. schedule()的流程图 --- mermaid()制作
![5dd5bd187072c29eaddcdd5c82a58348.png](https://i-blog.csdnimg.cn/blog_migrate/bd57a5f4b52db9b3144833e624464d38.jpeg)
![952d6ea50fa62b1838f9d107604d6039.png](https://i-blog.csdnimg.cn/blog_migrate/1ba1721f44a5cb0c697b9ac456061b40.jpeg)
R源码如下:
library(DiagrammeR)
library(dplyr)
add_box <- function(df, t, pref, suff) {
df$desc[df$type %in% t] %<>% paste0(pref, ., suff)
return(df)
}
fc <- getcsv('d:/linux-master/schedule_flow.csv') %>%
add_box(c('d', 'r'), '(', ')') %>%
add_box(c('s'), '[', ']') %>%
add_box(c('c'), '{', '}') %>%
mutate(seq = paste0(id, desc))
fc$seq = sub('^(d..+)((.*))', '1<br/>arg: 2', fc$seq, perl = T)
data <- select(fc, id, eid = tid) %>%
na.omit() %>%
mutate(sep = '-->') %>%
bind_rows(select(fc, id, eid = fid) %>% na.omit %>% mutate(sep = '-.->'))
mmd <- sapply(select(data, id, eid), qdapTools::lookup, select(fc, id, seq)) %>%
as.data.frame() %>%
bind_cols(select(data, sep)) %>%
{paste(
'graph TB',
with(., paste0(id, sep, eid, collapse = 'n')),
sep = 'n'
)}
mermaid(mmd)
![9a8ae8a30ef805815a313bebfdb43a4a.png](https://i-blog.csdnimg.cn/blog_migrate/732dfc7bc3017b4db7ca33be1af3d3c6.jpeg)
mmd是字符串,它的格式是:
[节点因子][左形状][内容][右形状]-->[节点因子][左形状][内容][右形状]
形状:
- () - 有圆角的矩形
- (()) - 圆形
- [] - 矩形
- {} - 菱形
- >] - 左侧凹三角, 右侧矩形
2. driver_register()流程图 - grVis制作
![856bcbdeb29bd2f5007aaaa0279b2fed.png](https://i-blog.csdnimg.cn/blog_migrate/bed8942a06fb24f89fbb8f464b02e0ad.jpeg)
![1fea21396449a679fc61330a2631396f.png](https://i-blog.csdnimg.cn/blog_migrate/1b9abd36819fae104cdb56d60b1d024e.jpeg)
贴出可以直接执行的代码(生成的代码没啥意思就不帖了):
grViz("
digraph {
graph [overlap = true]
edge [color = slategray, arrowhead = vee, penwidth = 5]
node [shape = oval, fontsize = 32, fontcolor = darkslategray, color = darkorange, width = 3, height = 2, penwidth = 3]
'1. int ret'; '2. struct device_driver *other'
node [shape = rectangle, fontsize = 32, fontcolor = darkslategray, color = steelblue, width = 4, height = 2, penwidth = 3]
'4. pr_err(`Driver %s was unable to register with bus_type %s because the bus was not initialized.n`,
drv->name, drv->bus->name)'; '5. return -EINVAL'; '7. printk(KERN_WARNING `Driver %s needs updating - please use `
`bus_type methodsn`, drv->name)'; '8. other = driver_find(drv->name, drv->bus)'; '10. printk(KERN_ERR `Error: Driver %s is already registered, `
`aborting...n`, drv->name)'; '11. return -EBUSY'; '12. ret = bus_add_driver(drv)'; '14. return ret'; '15. ret = driver_add_groups(drv, drv->groups)'; '17. bus_remove_driver(drv)'; '18. return ret'; '19. kobject_uevent(&drv->p->kobj, KOBJ_ADD)'; '20. return ret'
node [shape = diamond, fontsize = 32, fontcolor = darkslategray, color = mediumseagreen, width = 4, height = 3, penwidth = 4]
'3. !drv->bus->p'; '6. (drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)'; '9. other'; '13. ret'; '16. ret'
node [shape = point, fillcolor = slategray, color = gray, width = 1, height = 1]
'21. '
'1. int ret'->'2. struct device_driver *other'; '2. struct device_driver *other'->'3. !drv->bus->p'; '3. !drv->bus->p'->'4. pr_err(`Driver %s was unable to register with bus_type %s because the bus was not initialized.n`,
drv->name, drv->bus->name)'[color = forestgreen]; '4. pr_err(`Driver %s was unable to register with bus_type %s because the bus was not initialized.n`,
drv->name, drv->bus->name)'->'5. return -EINVAL'; '5. return -EINVAL'->'21. '; '6. (drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)'->'7. printk(KERN_WARNING `Driver %s needs updating - please use `
`bus_type methodsn`, drv->name)'[color = forestgreen]; '7. printk(KERN_WARNING `Driver %s needs updating - please use `
`bus_type methodsn`, drv->name)'->'8. other = driver_find(drv->name, drv->bus)'; '8. other = driver_find(drv->name, drv->bus)'->'9. other'; '9. other'->'10. printk(KERN_ERR `Error: Driver %s is already registered, `
`aborting...n`, drv->name)'[color = forestgreen]; '10. printk(KERN_ERR `Error: Driver %s is already registered, `
`aborting...n`, drv->name)'->'11. return -EBUSY'; '11. return -EBUSY'->'21. '; '12. ret = bus_add_driver(drv)'->'13. ret'; '13. ret'->'14. return ret'[color = forestgreen]; '14. return ret'->'21. '; '15. ret = driver_add_groups(drv, drv->groups)'->'16. ret'; '16. ret'->'17. bus_remove_driver(drv)'[color = forestgreen]; '17. bus_remove_driver(drv)'->'18. return ret'; '18. return ret'->'21. '; '19. kobject_uevent(&drv->p->kobj, KOBJ_ADD)'->'20. return ret'; '20. return ret'->'21. '; '3. !drv->bus->p'->'6. (drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)'[color = tomato]; '6. (drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)'->'8. other = driver_find(drv->name, drv->bus)'[color = tomato]; '9. other'->'12. ret = bus_add_driver(drv)'[color = tomato]; '13. ret'->'15. ret = driver_add_groups(drv, drv->groups)'[color = tomato]; '16. ret'->'19. kobject_uevent(&drv->p->kobj, KOBJ_ADD)'[color = tomato]
}
", width = 1900, height = 1470)
说白了就是按照一定的格式将node(节点)和edge(连线)在字符串中列出来, 有兴趣深入了解的可以移步下面examples:
DiagrammeR - Documentationrich-iannone.github.io![72ec9a03d0c4c4ba29ab555d91d65183.png](https://i-blog.csdnimg.cn/blog_migrate/617642ffb4b6c6c1474471828a6abcaf.jpeg)
就如视频所示,制作linux中任意一个C函数(遵循linux coding style)的流程图5分钟之内就能搞定
理一下设计思路:
- 首先弄清楚DiagrammeR::grViz和DiagrammeR::mermaid的数据格式 --- 节点和连线
- 节点即为函数中的每行代码 - 根据分类declaration, statement, conditional statement, return绘制不同的图形
- bash下需要将函数找到并获取函数体(function body)
- 过滤掉注释和空行(其实注释很重要应该保留, 未来再考虑添加吧)
- 将每个独立语句都merge成一行(linux kernel coding style会有很多statement占用多行)
- 每个statement做index以便生成语句的执行顺序
- 手动编辑生成最终的csv文件
- 导入R,并生成grViz/mermaid格式字符串
- 绘图
难点:
- 如何通过函数名找到函数的具体位置? - ctags! 它会生成一个tags文件, 直接到里面搜就OK了
- 3 ~ 7步需要用到大量的正则来完成,时间都花这上面了
最后附上本例使用的R包:
DiagrammeRrich-iannone.github.io![d49cf572ed728b141bac18690a3f47c5.png](https://i-blog.csdnimg.cn/blog_migrate/7663cb604e391891353c1b0848b9746b.png)
![6a63489b003ba3bd2e8d4b577c0ffd25.png](https://i-blog.csdnimg.cn/blog_migrate/61879a72d2fbf72315371ca43b0696fe.jpeg)
本专栏只生产干货,喜欢请关注:
数据及可视化zhuanlan.zhihu.com![e5bf33d6da820aa893132e19cb569376.png](https://i-blog.csdnimg.cn/blog_migrate/379ce3c911925480a2431aee462e4db2.jpeg)