python绘制基因结构图_利用python+graphviz绘制数据结构关系图和指定目录下头文件包含关系图...

作为一名linux系统下的C语言开发,日常工作中经常遇到两个问题:

一是分析代码过程中,各种数据结构互相关联,只通过代码很难理清系统中所有结构体的整体架构,影响代码消化的效率;

二是多层头文件嵌套包含,在新增需要被多处引用的结构体或者函数接口时,难以找到合适的地方放置结构体和函数接口的定义。

为解决这两个问题,用python分别写了两个脚本:

第一个脚本用于绘制关键数据结构的关联关系图,协助快速理解组织架构,加速理解代码逻辑;

第二个脚本用于分析指定目录下的头文件包含关系,协助新增结构体或者函数接口时快速找到合适的放置位置;

两个脚本绘图效果分别见下图1,图2。

图1.数据结构关联关系图

图2.头文件包含关系图(截取部分)

以下代码是用于分析结构体关联关系的python脚本(analysis_data_struct.py),使用方法如下:

1.在电脑上安装python和graphviz绘图工具(自行搜索,安装方法略);

2.把需要绘制关系图的关键数据结构复制粘贴到一个文本文件中;

3.把脚本中的保存数据结构文件路径(G:\git_repository\libreofficedraw\linux_4.18\plfc_struct )替换为自己的保存数据结构的文件路径(可自行修改脚本,通过参数传入文件路径);

4.执行命令 python analysis_data_struct.py >tmpfile; dot -Tsvg tmpfile -o xxxx.svg; 其中第一条命令使用python分析数据结构并生成用于绘图的dot语言,第二条命令利用graphviz根据tmpfile中的dot语言描述绘图。图形保存到xxxx.svg文件中;可以使用浏览器打开。

#!/usr/bin/python3

importos,re

prefix= '''digraph spdk {

graph [

rankdir = "LR"

//splines=polyline

//overlap=false

];

node [

fontsize = "16"

shape = "ellipse"\r

];

edge [

];'''middle_str= ''edge_list=[]

edge_string= ''cur_indentation_level=0

space4= ' 'space8= space4 +space4

space12= space4 +space8

space16= space4 +space12

node_database={}

node_database['created'] =[]

color_arrary= ['red', 'green', 'blue', 'black','blueviolet','brown', 'cadetblue','chocolate','crimson','cyan','darkgrey','deeppink','darkred']

with open(r'G:\git_repository\libreofficedraw\linux_4.18\plfc_struct', 'r') as file_input:

tmpline=file_input.readline()while(tmpline):

tmpline= re.sub(r'([^a-zA-Z0-9]const )', ' ', tmpline)#for match :struct device {

if re.search(r'struct\s*([0-9a-zA-Z_\-]+)\s*\{', tmpline):

m= re.search(r'struct\s*([0-9a-zA-Z_\-]+)\s*\{', tmpline)

cur_indentation_level+= 1

if (cur_indentation_level == 1):

node_name= m.group(1)

node_str= space4 + '\"' + node_name + '\" [\n' + space8 + 'label = \"

'+ node_name +'\l|\n' + space12 + '{|{\n'node_database['created'].append(node_name)try:

node_database[node_name]['node_str'] =node_strexcept:

node_database[node_name]={}

node_database[node_name]['node_str'] =node_str#for match :struct device *parent;

elif re.search(r'struct\s*([0-9a-zA-Z_\-]+)\s*(\**)(\s*)([0-9a-zA-Z_\-]+)\s*;', tmpline) and cur_indentation_level >0:

m= re.search(r'struct\s*([0-9a-zA-Z_\-]+)\s*(\**)(\s*)([0-9a-zA-Z_\-]+)\s*;', tmpline)

member_type= m.group(1)

node_database[node_name]['node_str'] += space16 + '' + m.group(2) + m.group(3) + m.group(4) + '\l|\n'

try:

node_database[member_type]['included_by'].append(node_name)except:try:

node_database[member_type]['included_by'] =[]

node_database[member_type]['included_by'].append(node_name)except:

node_database[member_type]={}

node_database[member_type]['included_by'] =[]

node_database[member_type]['included_by'].append(node_name)#print('%s included by %s'%(member_type, node_database[member_type]['included_by']))

if(member_type in node_database['created']):

tmp_edge_str= space4 + node_name + ':' + member_type + '->' + member_type + ':' + 'head'

if not tmp_edge_str inedge_list:

edge_list.append(tmp_edge_str)#for match : void *driver_data;

elif re.search(r'\s*[0-9a-zA-Z_\-]+\s*(\**[0-9a-zA-Z_\-]+)\s*;', tmpline) and cur_indentation_level >0:

m= re.search(r'\s*[0-9a-zA-Z_\-]+\s*(\**[0-9a-zA-Z_\-]+)\s*;', tmpline)

node_database[node_name]['node_str'] += space16 + '' + m.group(1) + '\l|\n'

#for match:const char *init_name;

elif re.search(r'(.*)\s+(\**)(\s*)([0-9a-zA-Z_\-]+\s*);', tmpline) and cur_indentation_level >0:

m= re.search(r'(.*)\s+(\**)(\s*)([0-9a-zA-Z_\-]+\s*);', tmpline)

node_database[node_name]['node_str'] += space16 + '' + m.group(2) + m.group(3) + m.group(4) + '\l|\n'

#for match:int *(*runtime_idle)(struct device *dev);

elif re.search(r'\s*[0-9a-zA-Z_\-]+\s*\**\s*\(\s*(\**\s*[0-9a-zA-Z_\-]+)\s*\)\s*\([^\)]*\)\s*;', tmpline) and cur_indentation_level >0:

m= re.search(r'\s*[0-9a-zA-Z_\-]+\s*\**\s*\(\s*(\**\s*[0-9a-zA-Z_\-]+)\s*\)\s*\([^\)]*\)\s*;', tmpline)

node_database[node_name]['node_str'] += space16 + ' (' + m.group(1) + ')\l|\n'

#for match: };

elif re.search(r'\s*\}\s*;', tmpline):if(cur_indentation_level >= 1):

cur_indentation_level-= 1

if (cur_indentation_level ==0):

node_database[node_name]['node_str'] += space12 + '}}\"\n'node_database[node_name]['node_str'] += space8 + 'shape = \"record\"\n' + space4 + '];\n'

if 'included_by' innode_database[node_name]:for parent_node in node_database[node_name]['included_by']:if parent_node in node_database['created']:

tmp_edge_str= space4 + parent_node + ':' + node_name + '->' + node_name + ':' + 'head'

if not tmp_edge_str inedge_list:

edge_list.append(tmp_edge_str)

tmpline=file_input.readline()for tmpnode in node_database['created']:

middle_str= middle_str + node_database[tmpnode]['node_str']for i, tmpstr inenumerate(edge_list):

edge_string+= tmpstr + '[color="' + color_arrary[i%len(color_arrary)] + '"]\n'

print(prefix + middle_str + '\n' + edge_string + '}')

以下为记录数据结构的文本文件(plfc_struct),用于测试。

structbus_type {const char *name;const char *dev_name;struct device *dev_root;const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);int (*num_vf)(struct device *dev);int (*dma_configure)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;structlock_class_key lock_key;boolneed_parent_lock;

};structpci_driver {structlist_head node;const char *name;const struct pci_device_id *id_table; /*Must be non-NULL for probe to be called*/

int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /*New device inserted*/

void (*remove)(struct pci_dev *dev); /*Device removed (NULL if not a hot-plug capable driver)*/

int (*suspend)(struct pci_dev *dev, pm_message_t state); /*Device suspended*/

int (*suspend_late)(struct pci_dev *dev, pm_message_t state);int (*resume_early)(struct pci_dev *dev);int (*resume) (struct pci_dev *dev); /*Device woken up*/

void (*shutdown) (struct pci_dev *dev);int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /*On PF*/

const struct pci_error_handlers *err_handler;const struct attribute_group **groups;structdevice_driver driver;structpci_dynids dynids;

};structdevice_driver {const char *name;struct bus_type *bus;struct module *owner;const char *mod_name; /*used for built-in modules*/

bool suppress_bind_attrs; /*disables bind/unbind via sysfs*/

enumprobe_type probe_type;const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;void (*coredump) (struct device *dev);struct driver_private *p;

};structdriver_private {structkobject kobj;structklist klist_devices;structklist_node knode_bus;struct module_kobject *mkobj;struct device_driver *driver;

};structkobject {const char *name;structlist_head entry;struct kobject *parent;struct kset *kset;struct kobj_type *ktype;struct kernfs_node *sd; /*sysfs directory entry*/

structkref kref;

#ifdef CONFIG_DEBUG_KOBJECT_RELEASEstructdelayed_work release;#endifunsignedint state_initialized:1;

unsignedint state_in_sysfs:1;

unsignedint state_add_uevent_sent:1;

unsignedint state_remove_uevent_sent:1;

unsignedint uevent_suppress:1;

};structsubsys_private {structkset subsys;struct kset *devices_kset;structlist_head interfaces;structmutex mutex;struct kset *drivers_kset;structklist klist_devices;structklist klist_drivers;structblocking_notifier_head bus_notifier;

unsignedint drivers_autoprobe:1;struct bus_type *bus;structkset glue_dirs;struct class *class;

};structkset {structlist_head list;

spinlock_t list_lock;structkobject kobj;const struct kset_uevent_ops *uevent_ops;

};structkobj_type {void (*release)(struct kobject *kobj);const struct sysfs_ops *sysfs_ops;struct attribute **default_attrs;const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);const void *(*namespace)(struct kobject *kobj);

};structsysfs_ops {

ssize_t (*show)(struct kobject *, struct attribute *, char *);

ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);

};structdev_pm_ops {int (*prepare)(struct device *dev);void (*complete)(struct device *dev);int (*suspend)(struct device *dev);int (*resume)(struct device *dev);int (*freeze)(struct device *dev);int (*thaw)(struct device *dev);int (*poweroff)(struct device *dev);int (*restore)(struct device *dev);int (*suspend_late)(struct device *dev);

};structkset_uevent_ops {int (* constfilter)(xxxxxxx);const char *(* const name)(struct kset *kset, struct kobject *kobj);int (* const uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);

};structqla_init_msix_entry {const char *name;

irq_handler_t handler;

};structattribute_group {const char *name;

umode_t (*is_visible)(struct kobject *, struct attribute *, int);

umode_t (*is_bin_visible)(struct kobject *,struct bin_attribute *, int);struct attribute **attrs;struct bin_attribute **bin_attrs;

};structbus_attribute {structattribute attr;

ssize_t (*show)(struct bus_type *bus, char *buf);

ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);

};structklist {

spinlock_t k_lock;structlist_head k_list;void (*get)(struct klist_node *);void (*put)(struct klist_node *);

} ;structpci_device_id {

__u32 vendor_device;/*Vendor and device ID or PCI_ANY_ID*/__u32 subvendor_subdevice;/*Subsystem ID's or PCI_ANY_ID*/__u32 class_class_mask;/*(class,subclass,prog-if) triplet*/kernel_ulong_t driver_data;/*Data private to the driver*/};structdevice {struct device *parent;struct device_private *p;structkobject kobj;const char *init_name; /*initial name of the device*/

const struct device_type *type;struct mutex mutex; /*mutex to synchronize calls to

* its driver.*/

struct bus_type *bus; /*type of bus device is on*/

struct device_driver *driver; /*which driver has allocated this

device*/

void *platform_data; /*Platform specific data, device

core doesn't touch it*/

void *driver_data; /*Driver data, set and get with

dev_set/get_drvdata*/

structdev_links_info links;const struct attribute_group **groups; /*optional groups*/

void (*release)(struct device *dev);struct iommu_group *iommu_group;struct iommu_fwspec *iommu_fwspec;

};structdev_links_info {structlist_head suppliers;structlist_head consumers;enumdl_dev_state status;

};structpci_dynids {

spinlock_tlock; /*Protects list, index*/

struct list_head list; /*For IDs added at runtime*/};以下结构体名称为全局变量,结构体成员为全局变量的类型,用于绘图时关联全局变量及其类型///

structqla2xxx_pci_driver {structpci_driver pci_driver;

};structpci_bus_type {structbus_type bus_type;

};structdriver_ktype {structkobj_type kobj_type;

};structdriver_sysfs_ops {structsysfs_ops sysfs_ops;

};structqla2xxx_pci_tbl{structpci_device_id pci_device_id;

};structbus_kset {structkset kset;

};structbus_uevent_ops {structkset_uevent_ops kset_uevent_ops;

};

以下脚本(analysis_head_file.py)用于分析指定目录下头文件包含关系,使用方法如下:

1.在电脑上安装python和graphviz绘图工具(自行搜索,安装方法略);

2.把脚本中的代码路径(G:\git_repository\linux-stable\linux-4.18\drivers\net\wireless\broadcom)替换为需要分析的文件路径(可自行修改脚本,通过参数传入文件路径);

3.执行命令 python analysis_head_file.py >tmpfile; dot -Tsvg tmpfile -o xxxx.svg; 其中第一条命令使用python分析数据结构并生成用于绘图的dot语言,第二条命令利用graphviz根据tmpfile中的dot语言描述绘图。图形保存到xxxx.svg文件中;可以使用浏览器打开。

#!/usr/bin/python3

importos,re

prefix= '''digraph spdk {

graph [

rankdir = "LR"

//splines=polyline

overlap=false

];

node [

fontsize = "16"

shape = "ellipse"\r

];

edge [

];'''

defget_head_file_list(path_file):

head_file_list=[]

with open(path_file,'r') as file_input:

tmpline=file_input.readline()while(tmpline):#to match #include < XXX/YYY.h >

m = re.search(r'#include\s*[\"]', tmpline)ifm:

head_file_list.append(re.sub(r'\-', '_', m.group(2)))#to match #include < XXX.h >

elif re.search(r'#include\s*[\"]', tmpline):

m= re.search(r'#include\s*[\"]', tmpline)

head_file_list.append(re.sub(r'\-', '_', m.group(1)))

tmpline=file_input.readline()returnhead_file_listdefbuild_node_from_file(file_path, file_name, edges, included_by):

i=0

space4= ' 'space8= space4 +space4

space12= space4 +space8

space16= space4 +space12

file_name_wo_h= re.search(r'([0-9a-zA-Z_\-]*)\.h', file_name).group(1)

file_name_wo_h= re.sub(r'\-', '_',file_name_wo_h)#print(file_name_wo_h)

node_str = space4 + '\"' + file_name_wo_h + '\" [\n' + space8 + 'label = \"

'+ file_name_wo_h +'.h\l|\n' + space12 + '{|{\n'headfilelist= ["aaa", "bbb"] #fake file list

headfilelist2 =get_head_file_list(os.path.join(file_path, file_name))#print('headfilelist2:')

#print(headfilelist2)

for headfile inheadfilelist2:

i+= 1

try:

included_by[headfile].append(file_name)except:

included_by[headfile]=[]

included_by[headfile].append(file_name)

node_str= node_str + space16 + '' + headfile + '.h\l|\n'tmp_edge_str= space4 + file_name_wo_h + ':' + headfile + '->' + headfile + ':' + 'head' #+ '[color="' + color_arrary[i%len(color_arrary)] + '"]\n'

try:if not tmp_edge_str inedges[headfile]:

edges[headfile].append(tmp_edge_str)except:

edges[headfile]=[]

edges[headfile].append(tmp_edge_str)

node_str= node_str + space12 + '}}\"\n'node_str= node_str + space8 + 'shape = \"record\"\n' + space4 + '];\n'

#print(included_by)

return {'node_str':node_str,'edges':edges}

edges={}

included_by={}

node_created=[]

middle_str= ''edge_string= ''color_arrary= ['red', 'green', 'blue', 'black','blueviolet','brown', 'cadetblue','chocolate','crimson','cyan','darkgrey','deeppink','darkred']for maindir, subdir, file_name_list in os.walk(r'G:\git_repository\linux-stable\linux-4.18\drivers\net\wireless\broadcom'):#('G:\git_repository\linux-stable\linux-4.18\drivers\usb'):

for tmpfile infile_name_list:if re.match(r'.*\.h', tmpfile):

result=build_node_from_file(maindir, tmpfile, edges, included_by)

node_created.append(re.search(r'([0-9a-zA-Z_\-]*)\.h', tmpfile).group(1))

middle_str= middle_str + '\n' + result['node_str']

edges= result['edges']##print(filelist2)

for tmpfile inedges:if tmpfile innode_created:for i,tmpstr inenumerate(edges[tmpfile]):

edge_string+= tmpstr + '[color="' + color_arrary[i%len(color_arrary)] + '"]\n'

print(prefix + middle_str + '\n' + edge_string + '}')

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值