confluence 制作流程图_[R+shell] 5分钟制作linux C函数流程图 - DiagrammeR

8cc14337c8bdb0b134d7492a16cef64c.png

grViz制作过程如下:

181e758af627a15a3255fb16ad24e470.png
可视化 - linux函数流程图https://www.zhihu.com/video/1092635656353816576

-----

推荐专栏另外两篇相关文章: linux C函数调用栈 以及 linux文件树

老白Walt:[R] 如何用树展示linux C函数调用栈 - collapsibleTree

老白Walt:[R] 展示linux文件树 - collapsibleTree


1. schedule()的流程图 --- mermaid()制作

5dd5bd187072c29eaddcdd5c82a58348.png

952d6ea50fa62b1838f9d107604d6039.png
schedule()流程图

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

mmd是字符串,它的格式是:

[节点因子][左形状][内容][右形状]-->[节点因子][左形状][内容][右形状]

形状:

  • () - 有圆角的矩形
  • (()) - 圆形
  • [] - 矩形
  • {} - 菱形
  • >] - 左侧凹三角, 右侧矩形

2. driver_register()流程图 - grVis制作

856bcbdeb29bd2f5007aaaa0279b2fed.png

1fea21396449a679fc61330a2631396f.png
driver_register()流程图

贴出可以直接执行的代码(生成的代码没啥意思就不帖了):

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 - Documentation​rich-iannone.github.io
72ec9a03d0c4c4ba29ab555d91d65183.png

就如视频所示,制作linux中任意一个C函数(遵循linux coding style)的流程图5分钟之内就能搞定

理一下设计思路:

  1. 首先弄清楚DiagrammeR::grViz和DiagrammeR::mermaid的数据格式 --- 节点和连线
  2. 节点即为函数中的每行代码 - 根据分类declaration, statement, conditional statement, return绘制不同的图形
  3. bash下需要将函数找到并获取函数体(function body)
  4. 过滤掉注释和空行(其实注释很重要应该保留, 未来再考虑添加吧)
  5. 将每个独立语句都merge成一行(linux kernel coding style会有很多statement占用多行)
  6. 每个statement做index以便生成语句的执行顺序
  7. 手动编辑生成最终的csv文件
  8. 导入R,并生成grViz/mermaid格式字符串
  9. 绘图

难点:

  • 如何通过函数名找到函数的具体位置? - ctags! 它会生成一个tags文件, 直接到里面搜就OK了
  • 3 ~ 7步需要用到大量的正则来完成,时间都花这上面了

最后附上本例使用的R包:

DiagrammeR​rich-iannone.github.io
d49cf572ed728b141bac18690a3f47c5.png
rich-iannone/DiagrammeR​github.com
6a63489b003ba3bd2e8d4b577c0ffd25.png

本专栏只生产干货,喜欢请关注:

数据及可视化​zhuanlan.zhihu.com
e5bf33d6da820aa893132e19cb569376.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值