2013-03-17 64 views
10

有沒有辦法用鏗鏘聲創建可以合理地放在頁面上的調用圖?爲帶有叮噹聲的文件創建調用圖

即給定:使用

#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

更新採取以上:設置頁面= 「8.5,11」 給出了以下幾點:

enter image description here

回答

6

我想的第一件事可以通過插入:

將圖形的方向從默認的從下到上的排名從左到右設置爲從左到右

...靠近.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文件以在(例如)一半之前插入額外的空白節點的組中的節點,以便該組分散在兩個等級而不是一個等級上。不過,我自己也沒有機會這樣做。

*請參閱埃姆登Gansner,埃萊夫塞里奧Koutsofios和斯蒂芬北(2006)Drawing graphs with dot,附錄B.

編輯:如何自動插入額外的節點。

給定一個文件.dottest1.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,並且我已經使用默認的從下到上排序而不是從左到右排序定義的排名,上面已經提出過。我不知道clang文件是由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

......這讓我們想要什麼,我想。

+0

肯定比我有更好的,但有沒有辦法隨機分裂一個等級,並使其顯示好像它是兩個級別(沒有明確插入虛擬節點) – soandos 2013-04-25 23:05:45

+0

是否有可能得到一個排名靠前的節點列表?我認爲,如果可以這樣做,腳本將更容易 – soandos 2013-04-25 23:14:52

+0

不幸的是,我不知道一種方法來分裂一個排名,而不插入虛擬節點。我嘗試過對邊緣加權不均勻,但不會調整'dot'佈局的節點的等級,這是由拓撲嚴格定義的。如果您使用某些其他佈局包(例如'neato'),則使用差分加權邊可以聚集一些節點並分隔其他節點。但是,您失去了使用'dot'獲得的等級順序。 – Simon 2013-04-25 23:26:35

相關問題