12

ページに合理的に収まるclangを使用してコールグラフを作成する方法はありますか?

すなわち与えられた:

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

私は現在得るここに画像の説明を入力

を使用して:

$ 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生成されたファイルがページ (任意の標準サイズ) に快適に収まるようにする方法はありますか?

注: C++ コードの呼び出しグラフの生成から取得した上記のコード

更新: page="8.5,11" を設定すると、次のようになります。

ここに画像の説明を入力

4

1 に答える 1

6

最初にすべきことは、以下を挿入して、グラフの方向をデフォルトの下から上へのランキングから左から右へ設定することだと思います。

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 座標 (if rankdir=TB) または Y座標 (if ) を持つノードの大きなグループを見つけてからrankdir=LR、元の.dotファイルを処理して前に余分な空白ノードを挿入することができます (たとえば)。グループが 1 つではなく 2 つのランクに分散されるように、そのグループ内のノードの半分。しかし、私はこれを自分で行う機会がありませんでした。

*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
}

...表示されているグラフを生成します。

ここに画像の説明を入力

...実行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

したがって、2 つのファイルを一緒に処理できるようになりました。Awk よりも Python の方が少し簡単なので、これには Python を使用します。この例では、ランク内のノード数を 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と、次のようになります。

ここに画像の説明を入力

... 私たちが望むものを与えてくれると思います。

于 2013-04-25T22:42:59.070 に答える