gpt4 book ai didi

clang - 使用 clang 为文件创建调用图

转载 作者:行者123 更新时间:2023-12-04 02:19:12 31 4
gpt4 key购买 nike

有没有办法用clang创建一个可以合理地适合页面的调用图?

即给出:

#include<iostream>
using namespace std;
int main()
{
int a;
cin>>a;
cout<<a;
cout<<a;
return 0;
}

我目前得到 enter image description here

通过使用:
$ clang++ main.cpp -S -emit-llvm -o - |
opt -analyze -std-link-opts -dot-callgraph
$ cat callgraph.dot | c++filt |
sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' |
gawk '/external node/{id=$1}$1!=id' | dot -Tpng -ocallgraph.png

(这似乎需要付出很多努力来做一些我没想到会如此困难的事情)。我想得到一些在水平轴上更合理的东西。 Unflatten似乎没有任何影响(至少对这个文件,对其他文件似乎影响很小)。

有没有办法确保 png生成的文件可以轻松适应页面(任何标准尺寸)?

注:以上代码取自 Generate calling graph for C++ code

更新:设置 page="8.5,11"给出以下内容:

enter image description here

最佳答案

我认为首先要做的是通过插入将图形的方向从默认的自下而上排名设置为从左到右:

rankdir=LR;

... 接近顶部 .dot文件,在第一个 { 之后.这应该使图形从左到右定向,从而使其对于具有长节点标签的这种情况更加紧凑。究竟如何做到这一点取决于 callgraph.dot 的格式。但是,假设它看起来像这样:
digraph G {
node [shape=rectangle];
...

......然后是这样的:
sed 's/digraph G {/digraph G { \n rankdir=LR;/'

...会做这项工作。

我过去采用的另一种方法是将虚拟节点插入边缘以减少具有相同等级的节点数量(因此将绘制在同一行中(使用 rankdir=TB ,这是默认值)或列(带有 rankdir=LR )。这在手动编写 .dot 文件时很简单,但很难编写脚本。

如果您想编写脚本,在某些边中插入额外的节点以将通常处于相同等级的节点分散到多个等级,您可以通过运行 dot -Tplain 来实现。输出一个纯文本文件*,其中包括(除其他外)具有每个节点中心的 X 和 Y 坐标的节点列表。然后,您可以使用 gawk要读取该列表,请找到具有相同 X 坐标(如果 rankdir=TB )或 Y 坐标(如果 rankdir=LR)的任何大组节点,然后处理原始 .dot文件以在(比如说)该组中的一半节点之前插入一个额外的空白节点,以便该组分布在两个等级而不是一个等级上。不过,我自己还没有机会这样做。

*参见 Emden Gansner、Eleftherios Koutsofios 和 Stephen North (2006) Drawing graphs with dot , 附录 B。

编辑:如何自动插入额外的节点。

给定一个 .dot文件 test1.dot如下:
digraph G {
n1 -> n20
n1 -> n21
n1 -> n22
n20 -> n3
n21 -> n3
n22 -> n3
}

...产生显示的图表。

enter image description here

... 正在运行 dot -Tplain test1.dot >test1.plain给出文件 test1.plain :
graph 1 2.75 2.5
node n1 1.375 2.25 0.75 0.5 n1 solid ellipse black lightgrey
node n20 0.375 1.25 0.75 0.5 n20 solid ellipse black lightgrey
node n21 1.375 1.25 0.75 0.5 n21 solid ellipse black lightgrey
node n22 2.375 1.25 0.75 0.5 n22 solid ellipse black lightgrey
node n3 1.375 0.25 0.75 0.5 n3 solid ellipse black lightgrey
edge n1 n20 4 1.1726 2.0394 1.0313 1.9019 0.83995 1.7159 0.68013 1.5605 solid black
edge n1 n21 4 1.375 1.9958 1.375 1.8886 1.375 1.7599 1.375 1.6405 solid black
edge n1 n22 4 1.5774 2.0394 1.7187 1.9019 1.9101 1.7159 2.0699 1.5605 solid black
edge n20 n3 4 0.57736 1.0394 0.71875 0.90191 0.91005 0.71592 1.0699 0.56054 solid black
edge n21 n3 4 1.375 0.99579 1.375 0.88865 1.375 0.7599 1.375 0.64045 solid black
edge n22 n3 4 2.1726 1.0394 2.0313 0.90191 1.8399 0.71592 1.6801 0.56054 solid black
stop

因此,我们现在可以一起处理这两个文件。为此,我将使用 Python,因为在 Python 中执行此操作比在 Awk 中执行要容易一些。为了这个例子,我将一个等级中的节点数限制为 2,并且我使用了默认的自下而上排序而不是从左到右的排序所定义的等级。上面已经建议了。我不知道到底是什么类型的 .dot clang 正在输出文件,因此可能需要稍微修改此示例以将其考虑在内。
import sys,re;

plain = open(sys.argv[2])
nodesInRank = {}
for line in plain:
x = line.split()
rankloc = 3 # rank is in the y column for the vertical case.
# Change this to rankloc = 2 for the horizontal case
if len(x) > 0 and x[0] == "node":
nodesInRank[x[rankloc]] = nodesInRank.get(x[rankloc],[]) + [x[1]]

maxNodesInRank = 2
dummies = set()
for n in nodesInRank.values():
if len(n) > maxNodesInRank:
dummies = dummies | set(n[:len(n)//2])

dot = open(sys.argv[1])
for line in dot:
line = line.rstrip()
line2 = ""
for d in dummies:
m = "-> +%s" % (d)
if re.search(m,line):
line = re.sub(m,"-> dummy_%s [dir = none]\n dummy_%s -> %s" % (d,d,d),line)
line2 = '\tdummy_%s [shape=none, width=0, height=0, label=""];' % (d)
print (line)
if len(line2) > 0:
print (line2)

鉴于这个 Python 脚本,我称之为 breakrank.py ,我现在可以将它运行为:
python breakrank.py test1.dot test1.plain >test_dummy.dot

... 将以下内容放入 test_dummy.dot :
digraph G {
n1 -> dummy_n20 [dir = none]
dummy_n20 -> n20
dummy_n20 [shape=none, width=0, height=0, label=""];
n1 -> n21
n1 -> n22
n20 -> n3
n21 -> n3
n22 -> n3
}

如果我们通过 dot 运行它,我们现在得到:

enter image description here

...这给了我们想要的东西,我想。

关于clang - 使用 clang 为文件创建调用图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15458738/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com