llvm.org GIT mirror llvm / ae0fbfb
[XRay] A tool for Comparing xray function call graphs Summary: This is a tool for comparing the function graphs produced by the llvm-xray graph too. It takes the form of a new subcommand of the llvm-xray tool 'graph-diff'. This initial version of the patch is very rough, but it is close to feature complete. Depends on D29363 Reviewers: dblaikie, dberris Reviewed By: dberris Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D29320 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301160 91177308-0d34-0410-b5e6-96231b3b80d8 Dean Michael Berris 2 years ago
11 changed file(s) with 1093 addition(s) and 138 deletion(s). Raw diff Collapse all Expand all
0 ---
1 header:
2 version: 1
3 type: 0
4 constant-tsc: true
5 nonstop-tsc: true
6 cycle-frequency: 1
7 records:
8 - { type: 0, func-id: 1, cpu: 1, thread: 111, kind: function-enter, tsc: 10000 }
9 - { type: 0, func-id: 1, cpu: 1, thread: 111, kind: function-exit, tsc: 10010 }
10 - { type: 0, func-id: 2, cpu: 1, thread: 111, kind: function-enter, tsc: 10100 }
11 - { type: 0, func-id: 2, cpu: 1, thread: 111, kind: function-exit, tsc: 10120 }
12 - { type: 0, func-id: 3, cpu: 1, thread: 111, kind: function-enter, tsc: 10200 }
13 - { type: 0, func-id: 3, cpu: 1, thread: 111, kind: function-exit, tsc: 10230 }
14 - { type: 0, func-id: 4, cpu: 1, thread: 111, kind: function-enter, tsc: 10300 }
15 - { type: 0, func-id: 4, cpu: 1, thread: 111, kind: function-exit, tsc: 10340 }
16 - { type: 0, func-id: 5, cpu: 1, thread: 111, kind: function-enter, tsc: 10400 }
17 - { type: 0, func-id: 5, cpu: 1, thread: 111, kind: function-exit, tsc: 10450 }
18 - { type: 0, func-id: 6, cpu: 1, thread: 111, kind: function-enter, tsc: 10500 }
19 - { type: 0, func-id: 6, cpu: 1, thread: 111, kind: function-exit, tsc: 10560 }
20 - { type: 0, func-id: 7, cpu: 1, thread: 111, kind: function-enter, tsc: 10600 }
21 - { type: 0, func-id: 7, cpu: 1, thread: 111, kind: function-exit, tsc: 10670 }
22 - { type: 0, func-id: 8, cpu: 1, thread: 111, kind: function-enter, tsc: 10700 }
23 - { type: 0, func-id: 8, cpu: 1, thread: 111, kind: function-exit, tsc: 10780 }
24 - { type: 0, func-id: 9, cpu: 1, thread: 111, kind: function-enter, tsc: 10800 }
25 - { type: 0, func-id: 9, cpu: 1, thread: 111, kind: function-exit, tsc: 10890 }
26 - { type: 0, func-id: 11, cpu: 1, thread: 111, kind: function-enter, tsc: 10900 }
27 - { type: 0, func-id: 11, cpu: 1, thread: 111, kind: function-exit, tsc: 10910 }
28 ---
0 ---
1 header:
2 version: 1
3 type: 0
4 constant-tsc: true
5 nonstop-tsc: true
6 cycle-frequency: 1
7 records:
8 - { type: 0, func-id: 1, cpu: 1, thread: 111, kind: function-enter, tsc: 10000 }
9 - { type: 0, func-id: 1, cpu: 1, thread: 111, kind: function-exit, tsc: 10090 }
10 - { type: 0, func-id: 2, cpu: 1, thread: 111, kind: function-enter, tsc: 10100 }
11 - { type: 0, func-id: 2, cpu: 1, thread: 111, kind: function-exit, tsc: 10180 }
12 - { type: 0, func-id: 3, cpu: 1, thread: 111, kind: function-enter, tsc: 10200 }
13 - { type: 0, func-id: 3, cpu: 1, thread: 111, kind: function-exit, tsc: 10270 }
14 - { type: 0, func-id: 4, cpu: 1, thread: 111, kind: function-enter, tsc: 10300 }
15 - { type: 0, func-id: 4, cpu: 1, thread: 111, kind: function-exit, tsc: 10360 }
16 - { type: 0, func-id: 5, cpu: 1, thread: 111, kind: function-enter, tsc: 10400 }
17 - { type: 0, func-id: 5, cpu: 1, thread: 111, kind: function-exit, tsc: 10450 }
18 - { type: 0, func-id: 6, cpu: 1, thread: 111, kind: function-enter, tsc: 10500 }
19 - { type: 0, func-id: 6, cpu: 1, thread: 111, kind: function-exit, tsc: 10540 }
20 - { type: 0, func-id: 7, cpu: 1, thread: 111, kind: function-enter, tsc: 10600 }
21 - { type: 0, func-id: 7, cpu: 1, thread: 111, kind: function-exit, tsc: 10630 }
22 - { type: 0, func-id: 8, cpu: 1, thread: 111, kind: function-enter, tsc: 10700 }
23 - { type: 0, func-id: 8, cpu: 1, thread: 111, kind: function-exit, tsc: 10720 }
24 - { type: 0, func-id: 9, cpu: 1, thread: 111, kind: function-enter, tsc: 10800 }
25 - { type: 0, func-id: 9, cpu: 1, thread: 111, kind: function-exit, tsc: 10810 }
26 - { type: 0, func-id: 10, cpu: 1, thread: 111, kind: function-enter, tsc: 10900 }
27 - { type: 0, func-id: 10, cpu: 1, thread: 111, kind: function-exit, tsc: 10910 }
28 ---
29
1818 - { id: 8, address: 0x9, function: 0x8, kind: function-exit, always-instrument: true}
1919 - { id: 9, address: 0x9, function: 0x9, kind: function-enter, always-instrument: true}
2020 - { id: 9, address: 0xA, function: 0x9, kind: function-exit, always-instrument: true}
21 - { id: 10, address: 0xA, function: 0xA, kind: function-enter, always-instrument: true}
22 - { id: 10, address: 0xB, function: 0xA, kind: function-exit, always-instrument: true}
23 - { id: 11, address: 0xB, function: 0xB, kind: function-enter, always-instrument: true}
24 - { id: 11, address: 0xC, function: 0xB, kind: function-exit, always-instrument: true}
2125 ...
0 #RUN: llvm-xray graph-diff -o - -c min -b min -m %S/Inputs/simple-instrmap.yaml \
1 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
2 #RUN: | FileCheck %s -check-prefix=VCEC
3 #RUN: llvm-xray graph-diff -o - -c min -m %S/Inputs/simple-instrmap.yaml \
4 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
5 #RUN: | FileCheck %s -check-prefix=EC
6 #RUN: llvm-xray graph-diff -o - -b min -m %S/Inputs/simple-instrmap.yaml \
7 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
8 #RUN: | FileCheck %s -check-prefix=VC
9 #RUN: llvm-xray graph-diff -o - -e min -v min -m %S/Inputs/simple-instrmap.yaml \
10 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
11 #RUN: | FileCheck %s -check-prefix=ELVL
12 #RUN: llvm-xray graph-diff -o - -e min -m %S/Inputs/simple-instrmap.yaml \
13 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
14 #RUN: | FileCheck %s -check-prefix=EL
15 #RUN: llvm-xray graph-diff -o - -v min -m %S/Inputs/simple-instrmap.yaml \
16 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
17 #RUN: | FileCheck %s -check-prefix=VL
18 #RUN: llvm-xray graph-diff -o - -v min -b min -m %S/Inputs/simple-instrmap.yaml \
19 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
20 #RUN: | FileCheck %s -check-prefix=VLVC
21 #RUN: llvm-xray graph-diff -o - -e min -c min -m %S/Inputs/simple-instrmap.yaml \
22 #RUN: %S/Inputs/graph-diff-A.yaml %S/Inputs/graph-diff-B.yaml \
23 #RUN: | FileCheck %s -check-prefix=ELEC
24
25 #VCEC: digraph xrayDiff {
26 #VCEC-DAG: F[[F0NO:[0-9]+]] [label="F0"]
27 #VCEC-DAG: F[[N1NO:[0-9]+]] [label="#1" color="#276419"]
28 #VCEC-DAG: F[[N2NO:[0-9]+]] [label="#2" color="#276419"]
29 #VCEC-DAG: F[[N3NO:[0-9]+]] [label="#3" color="#276419"]
30 #VCEC-DAG: F[[N4NO:[0-9]+]] [label="#4" color="#9BCF61"]
31 #VCEC-DAG: F[[N5NO:[0-9]+]] [label="#5" color="#F7F7F7"]
32 #VCEC-DAG: F[[N6NO:[0-9]+]] [label="#6" color="#F5C4E0"]
33 #VCEC-DAG: F[[N7NO:[0-9]+]] [label="#7" color="#E17FB4"]
34 #VCEC-DAG: F[[N8NO:[0-9]+]] [label="#8" color="#CB3088"]
35 #VCEC-DAG: F[[N9NO:[0-9]+]] [label="#9" color="#AD0E69"]
36 #VCEC-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
37 #VCEC-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
38 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="" color="#276419" labelfontcolor="#276419" penwidth=8.00]
39 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="" color="#276419" labelfontcolor="#276419" penwidth=3.00]
40 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="" color="#276419" labelfontcolor="#276419" penwidth=1.33]
41 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="" color="#9BCF61" labelfontcolor="#9BCF61" penwidth=1.00]
42 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="" color="#F7F7F7" labelfontcolor="#F7F7F7" penwidth=1.00]
43 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="" color="#F5C4E0" labelfontcolor="#F5C4E0" penwidth=1.00]
44 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="" color="#E17FB4" labelfontcolor="#E17FB4" penwidth=1.00]
45 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="" color="#CB3088" labelfontcolor="#CB3088" penwidth=1.00]
46 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="" color="#AD0E69" labelfontcolor="#AD0E69" penwidth=1.00]
47 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
48 #VCEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
49 #VCEC-NEXT:}
50
51
52 #EC: digraph xrayDiff {
53 #EC-DAG: F[[F0NO:[0-9]+]] [label="F0"]
54 #EC-DAG: F[[N1NO:[0-9]+]] [label="#1" color="black"]
55 #EC-DAG: F[[N2NO:[0-9]+]] [label="#2" color="black"]
56 #EC-DAG: F[[N3NO:[0-9]+]] [label="#3" color="black"]
57 #EC-DAG: F[[N4NO:[0-9]+]] [label="#4" color="black"]
58 #EC-DAG: F[[N5NO:[0-9]+]] [label="#5" color="black"]
59 #EC-DAG: F[[N6NO:[0-9]+]] [label="#6" color="black"]
60 #EC-DAG: F[[N7NO:[0-9]+]] [label="#7" color="black"]
61 #EC-DAG: F[[N8NO:[0-9]+]] [label="#8" color="black"]
62 #EC-DAG: F[[N9NO:[0-9]+]] [label="#9" color="black"]
63 #EC-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
64 #EC-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
65 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="" color="#276419" labelfontcolor="#276419" penwidth=8.00]
66 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="" color="#276419" labelfontcolor="#276419" penwidth=3.00]
67 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="" color="#276419" labelfontcolor="#276419" penwidth=1.33]
68 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="" color="#9BCF61" labelfontcolor="#9BCF61" penwidth=1.00]
69 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="" color="#F7F7F7" labelfontcolor="#F7F7F7" penwidth=1.00]
70 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="" color="#F5C4E0" labelfontcolor="#F5C4E0" penwidth=1.00]
71 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="" color="#E17FB4" labelfontcolor="#E17FB4" penwidth=1.00]
72 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="" color="#CB3088" labelfontcolor="#CB3088" penwidth=1.00]
73 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="" color="#AD0E69" labelfontcolor="#AD0E69" penwidth=1.00]
74 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
75 #EC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
76 #EC-NEXT:}
77
78 #VC: digraph xrayDiff {
79 #VC-DAG: F[[F0NO:[0-9]+]] [label="F0"]
80 #VC-DAG: F[[N1NO:[0-9]+]] [label="#1" color="#276419"]
81 #VC-DAG: F[[N2NO:[0-9]+]] [label="#2" color="#276419"]
82 #VC-DAG: F[[N3NO:[0-9]+]] [label="#3" color="#276419"]
83 #VC-DAG: F[[N4NO:[0-9]+]] [label="#4" color="#9BCF61"]
84 #VC-DAG: F[[N5NO:[0-9]+]] [label="#5" color="#F7F7F7"]
85 #VC-DAG: F[[N6NO:[0-9]+]] [label="#6" color="#F5C4E0"]
86 #VC-DAG: F[[N7NO:[0-9]+]] [label="#7" color="#E17FB4"]
87 #VC-DAG: F[[N8NO:[0-9]+]] [label="#8" color="#CB3088"]
88 #VC-DAG: F[[N9NO:[0-9]+]] [label="#9" color="#AD0E69"]
89 #VC-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
90 #VC-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
91 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="" color="black" labelfontcolor="black" penwidth=1.00]
92 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="" color="black" labelfontcolor="black" penwidth=1.00]
93 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="" color="black" labelfontcolor="black" penwidth=1.00]
94 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="" color="black" labelfontcolor="black" penwidth=1.00]
95 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="" color="black" labelfontcolor="black" penwidth=1.00]
96 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="" color="black" labelfontcolor="black" penwidth=1.00]
97 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="" color="black" labelfontcolor="black" penwidth=1.00]
98 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="" color="black" labelfontcolor="black" penwidth=1.00]
99 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="" color="black" labelfontcolor="black" penwidth=1.00]
100 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
101 #VC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
102 #VC-NEXT:}
103
104 #ELVL: digraph xrayDiff {
105 #ELVL-NEXT: node [shape=record]
106 #ELVL-DAG: F[[F0NO:[0-9]+]] [label="F0"]
107 #ELVL-DAG: F[[N1NO:[0-9]+]] [label="{#1|800.00%}" color="black"]
108 #ELVL-DAG: F[[N2NO:[0-9]+]] [label="{#2|300.00%}" color="black"]
109 #ELVL-DAG: F[[N3NO:[0-9]+]] [label="{#3|133.33%}" color="black"]
110 #ELVL-DAG: F[[N4NO:[0-9]+]] [label="{#4|50.00%}" color="black"]
111 #ELVL-DAG: F[[N5NO:[0-9]+]] [label="{#5|0.00%}" color="black"]
112 #ELVL-DAG: F[[N6NO:[0-9]+]] [label="{#6|-33.33%}" color="black"]
113 #ELVL-DAG: F[[N7NO:[0-9]+]] [label="{#7|-57.14%}" color="black"]
114 #ELVL-DAG: F[[N8NO:[0-9]+]] [label="{#8|-75.00%}" color="black"]
115 #ELVL-DAG: F[[N9NO:[0-9]+]] [label="{#9|-88.89%}" color="black"]
116 #ELVL-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
117 #ELVL-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
118 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="800.00%" color="black" labelfontcolor="black" penwidth=1.00]
119 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="300.00%" color="black" labelfontcolor="black" penwidth=1.00]
120 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="133.33%" color="black" labelfontcolor="black" penwidth=1.00]
121 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="50.00%" color="black" labelfontcolor="black" penwidth=1.00]
122 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="0.00%" color="black" labelfontcolor="black" penwidth=1.00]
123 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="-33.33%" color="black" labelfontcolor="black" penwidth=1.00]
124 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="-57.14%" color="black" labelfontcolor="black" penwidth=1.00]
125 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="-75.00%" color="black" labelfontcolor="black" penwidth=1.00]
126 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="-88.89%" color="black" labelfontcolor="black" penwidth=1.00]
127 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
128 #ELVL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
129 #ELVL-NEXT:}
130
131 #EL: digraph xrayDiff {
132 #EL-DAG: F[[F0NO:[0-9]+]] [label="F0"]
133 #EL-DAG: F[[N1NO:[0-9]+]] [label="#1" color="black"]
134 #EL-DAG: F[[N2NO:[0-9]+]] [label="#2" color="black"]
135 #EL-DAG: F[[N3NO:[0-9]+]] [label="#3" color="black"]
136 #EL-DAG: F[[N4NO:[0-9]+]] [label="#4" color="black"]
137 #EL-DAG: F[[N5NO:[0-9]+]] [label="#5" color="black"]
138 #EL-DAG: F[[N6NO:[0-9]+]] [label="#6" color="black"]
139 #EL-DAG: F[[N7NO:[0-9]+]] [label="#7" color="black"]
140 #EL-DAG: F[[N8NO:[0-9]+]] [label="#8" color="black"]
141 #EL-DAG: F[[N9NO:[0-9]+]] [label="#9" color="black"]
142 #EL-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
143 #EL-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
144 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="800.00%" color="black" labelfontcolor="black" penwidth=1.00]
145 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="300.00%" color="black" labelfontcolor="black" penwidth=1.00]
146 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="133.33%" color="black" labelfontcolor="black" penwidth=1.00]
147 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="50.00%" color="black" labelfontcolor="black" penwidth=1.00]
148 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="0.00%" color="black" labelfontcolor="black" penwidth=1.00]
149 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="-33.33%" color="black" labelfontcolor="black" penwidth=1.00]
150 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="-57.14%" color="black" labelfontcolor="black" penwidth=1.00]
151 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="-75.00%" color="black" labelfontcolor="black" penwidth=1.00]
152 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="-88.89%" color="black" labelfontcolor="black" penwidth=1.00]
153 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
154 #EL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
155 #EL-NEXT:}
156
157 #VL: digraph xrayDiff {
158 #VL-NEXT: node [shape=record]
159 #VL-DAG: F[[F0NO:[0-9]+]] [label="F0"]
160 #VL-DAG: F[[N1NO:[0-9]+]] [label="{#1|800.00%}" color="black"]
161 #VL-DAG: F[[N2NO:[0-9]+]] [label="{#2|300.00%}" color="black"]
162 #VL-DAG: F[[N3NO:[0-9]+]] [label="{#3|133.33%}" color="black"]
163 #VL-DAG: F[[N4NO:[0-9]+]] [label="{#4|50.00%}" color="black"]
164 #VL-DAG: F[[N5NO:[0-9]+]] [label="{#5|0.00%}" color="black"]
165 #VL-DAG: F[[N6NO:[0-9]+]] [label="{#6|-33.33%}" color="black"]
166 #VL-DAG: F[[N7NO:[0-9]+]] [label="{#7|-57.14%}" color="black"]
167 #VL-DAG: F[[N8NO:[0-9]+]] [label="{#8|-75.00%}" color="black"]
168 #VL-DAG: F[[N9NO:[0-9]+]] [label="{#9|-88.89%}" color="black"]
169 #VL-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
170 #VL-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
171 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="" color="black" labelfontcolor="black" penwidth=1.00]
172 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="" color="black" labelfontcolor="black" penwidth=1.00]
173 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="" color="black" labelfontcolor="black" penwidth=1.00]
174 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="" color="black" labelfontcolor="black" penwidth=1.00]
175 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="" color="black" labelfontcolor="black" penwidth=1.00]
176 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="" color="black" labelfontcolor="black" penwidth=1.00]
177 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="" color="black" labelfontcolor="black" penwidth=1.00]
178 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="" color="black" labelfontcolor="black" penwidth=1.00]
179 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="" color="black" labelfontcolor="black" penwidth=1.00]
180 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
181 #VL-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
182 #VL-NEXT:}
183
184 #VLVC: digraph xrayDiff {
185 #VLVC-NEXT: node [shape=record]
186 #VLVC-DAG: F[[F0NO:[0-9]+]] [label="F0"]
187 #VLVC-DAG: F[[N1NO:[0-9]+]] [label="{#1|800.00%}" color="#276419"]
188 #VLVC-DAG: F[[N2NO:[0-9]+]] [label="{#2|300.00%}" color="#276419"]
189 #VLVC-DAG: F[[N3NO:[0-9]+]] [label="{#3|133.33%}" color="#276419"]
190 #VLVC-DAG: F[[N4NO:[0-9]+]] [label="{#4|50.00%}" color="#9BCF61"]
191 #VLVC-DAG: F[[N5NO:[0-9]+]] [label="{#5|0.00%}" color="#F7F7F7"]
192 #VLVC-DAG: F[[N6NO:[0-9]+]] [label="{#6|-33.33%}" color="#F5C4E0"]
193 #VLVC-DAG: F[[N7NO:[0-9]+]] [label="{#7|-57.14%}" color="#E17FB4"]
194 #VLVC-DAG: F[[N8NO:[0-9]+]] [label="{#8|-75.00%}" color="#CB3088"]
195 #VLVC-DAG: F[[N9NO:[0-9]+]] [label="{#9|-88.89%}" color="#AD0E69"]
196 #VLVC-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
197 #VLVC-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
198 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="" color="black" labelfontcolor="black" penwidth=1.00]
199 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="" color="black" labelfontcolor="black" penwidth=1.00]
200 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="" color="black" labelfontcolor="black" penwidth=1.00]
201 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="" color="black" labelfontcolor="black" penwidth=1.00]
202 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="" color="black" labelfontcolor="black" penwidth=1.00]
203 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="" color="black" labelfontcolor="black" penwidth=1.00]
204 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="" color="black" labelfontcolor="black" penwidth=1.00]
205 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="" color="black" labelfontcolor="black" penwidth=1.00]
206 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="" color="black" labelfontcolor="black" penwidth=1.00]
207 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
208 #VLVC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
209 #VLVC-NEXT:}
210
211 #ELEC: digraph xrayDiff {
212 #ELEC-DAG: F[[F0NO:[0-9]+]] [label="F0"]
213 #ELEC-DAG: F[[N1NO:[0-9]+]] [label="#1" color="black"]
214 #ELEC-DAG: F[[N2NO:[0-9]+]] [label="#2" color="black"]
215 #ELEC-DAG: F[[N3NO:[0-9]+]] [label="#3" color="black"]
216 #ELEC-DAG: F[[N4NO:[0-9]+]] [label="#4" color="black"]
217 #ELEC-DAG: F[[N5NO:[0-9]+]] [label="#5" color="black"]
218 #ELEC-DAG: F[[N6NO:[0-9]+]] [label="#6" color="black"]
219 #ELEC-DAG: F[[N7NO:[0-9]+]] [label="#7" color="black"]
220 #ELEC-DAG: F[[N8NO:[0-9]+]] [label="#8" color="black"]
221 #ELEC-DAG: F[[N9NO:[0-9]+]] [label="#9" color="black"]
222 #ELEC-DAG: F[[NANO:[0-9]+]] [label="#10" color="#00FF00"]
223 #ELEC-DAG: F[[NBNO:[0-9]+]] [label="#11" color="#FF0000"]
224 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N1NO]] [tooltip="F0 -> #1" label="800.00%" color="#276419" labelfontcolor="#276419" penwidth=8.00]
225 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N2NO]] [tooltip="F0 -> #2" label="300.00%" color="#276419" labelfontcolor="#276419" penwidth=3.00]
226 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N3NO]] [tooltip="F0 -> #3" label="133.33%" color="#276419" labelfontcolor="#276419" penwidth=1.33]
227 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N4NO]] [tooltip="F0 -> #4" label="50.00%" color="#9BCF61" labelfontcolor="#9BCF61" penwidth=1.00]
228 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N5NO]] [tooltip="F0 -> #5" label="0.00%" color="#F7F7F7" labelfontcolor="#F7F7F7" penwidth=1.00]
229 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N6NO]] [tooltip="F0 -> #6" label="-33.33%" color="#F5C4E0" labelfontcolor="#F5C4E0" penwidth=1.00]
230 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N7NO]] [tooltip="F0 -> #7" label="-57.14%" color="#E17FB4" labelfontcolor="#E17FB4" penwidth=1.00]
231 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N8NO]] [tooltip="F0 -> #8" label="-75.00%" color="#CB3088" labelfontcolor="#CB3088" penwidth=1.00]
232 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[N9NO]] [tooltip="F0 -> #9" label="-88.89%" color="#AD0E69" labelfontcolor="#AD0E69" penwidth=1.00]
233 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NANO]] [tooltip="F0 -> #10" label="" color="#00FF00" labelfontcolor="#00FF00" penwidth=1.00]
234 #ELEC-DAG: F{{.*}}[[F0NO]] -> F{{.*}}[[NBNO]] [tooltip="F0 -> #11" label="" color="#FF0000" labelfontcolor="#FF0000" penwidth=1.00]
235 #ELEC-NEXT:}
236
237
1313 xray-extract.cc
1414 xray-extract.cc
1515 xray-graph.cc
16 xray-graph-diff.cc
1617 xray-registry.cc)
1718
1819 add_llvm_tool(llvm-xray llvm-xray.cc ${LLVM_XRAY_TOOLS})
1010 //
1111 //===----------------------------------------------------------------------===//
1212 #include
13 #include
1314
1415 #include "xray-color-helper.h"
1516 #include "llvm/Support/FormatVariadic.h"
4142 std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
4243 std::make_tuple(2, 56, 88)}};
4344
45 // Sequential Maps extend the last colors given out of range inputs.
46 static const std::tuple SequentialBounds[][2] = {
47 {// The Bounds for the greys color scheme
48 std::make_tuple(255, 255, 255), std::make_tuple(0, 0, 0)},
49 {// The Bounds for the OrRd color Scheme
50 std::make_tuple(255, 247, 236), std::make_tuple(127, 0, 0)},
51 {// The Bounds for the PuBu color Scheme
52 std::make_tuple(255, 247, 251), std::make_tuple(2, 56, 88)}};
53
4454 ColorHelper::ColorHelper(ColorHelper::SequentialScheme S)
45 : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast(S)]) {}
55 : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast(S)]),
56 BoundMap(SequentialBounds[static_cast(S)]) {}
4657
4758 // Diverging ColorMaps, which are used to represent information
4859 // representing differenes, or a range that goes from negative to positive.
5768 std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
5869 std::make_tuple(39, 100, 25)}};
5970
71 // Diverging maps use out of bounds ranges to show missing data. Missing Right
72 // Being below min, and missing left being above max.
73 static const std::tuple DivergingBounds[][2] = {
74 {// The PiYG color scheme has green and red for missing right and left
75 // respectively.
76 std::make_tuple(255, 0, 0), std::make_tuple(0, 255, 0)}};
77
6078 ColorHelper::ColorHelper(ColorHelper::DivergingScheme S)
61 : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast(S)]) {}
79 : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast(S)]),
80 BoundMap(DivergingBounds[static_cast(S)]) {}
6281
6382 // Takes a tuple of uint8_ts representing a color in RGB and converts them to
6483 // HSV represented by a tuple of doubles
7796
7897 double C = Scaled[Max] - Scaled[Min];
7998
80 double HPrime = (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
99 double HPrime =
100 (C == 0) ? 0 : (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
81101 HPrime = HPrime + 2.0 * Max;
82102
83103 double H = (HPrime < 0) ? (HPrime + 6.0) * 60
84104 : HPrime * 60; // Scale to between 0 and 360
85
86105 double V = Scaled[Max];
87106
88107 double S = (V == 0.0) ? 0.0 : C / V;
163182 std::tuple
164183 ColorHelper::getColorTuple(double Point) const {
165184 assert(!ColorMap.empty() && "ColorMap must not be empty!");
185 assert(!BoundMap.empty() && "BoundMap must not be empty!");
186
187 if (Point < MinIn)
188 return BoundMap[0];
189 if (Point > MaxIn)
190 return BoundMap[1];
191
166192 size_t MaxIndex = ColorMap.size() - 1;
167193 double IntervalWidth = MaxIn - MinIn;
168194 double OffsetP = Point - MinIn;
4545 double MaxIn;
4646
4747 ArrayRef> ColorMap;
48 ArrayRef> BoundMap;
4849
4950 public:
5051 /// Enum of the availible Sequential Color Schemes
7273
7374 std::string getColorString(double Point) const;
7475
76 // Get the Default color, at the moment allways black.
77 std::tuple getDefaultColorTuple() const {
78 return std::make_tuple(0, 0, 0);
79 }
80
81 std::string getDefaultColorString() const { return "black"; }
82
7583 // Convert a tuple to a string
7684 static std::string getColorString(std::tuple t);
7785 };
78 }
79 }
86 } // namespace xray
87 } // namespace llvm
8088 #endif
0 //===-- xray-graph-diff.cc - XRay Function Call Graph Renderer ------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Generate a DOT file to represent the function call graph encountered in
10 // the trace.
11 //
12 //===----------------------------------------------------------------------===//
13 #include
14 #include
15 #include
16 #include
17
18 #include "xray-graph-diff.h"
19 #include "xray-graph.h"
20 #include "xray-registry.h"
21
22 #include "xray-color-helper.h"
23 #include "llvm/ADT/iterator_range.h"
24 #include "llvm/Support/FormatVariadic.h"
25 #include "llvm/XRay/Trace.h"
26
27 using namespace llvm;
28 using namespace xray;
29
30 static cl::SubCommand GraphDiff("graph-diff",
31 "Generate diff of function-call graphs");
32 static cl::opt GraphDiffInput1(cl::Positional,
33 cl::desc(""),
34 cl::Required, cl::sub(GraphDiff));
35 static cl::opt GraphDiffInput2(cl::Positional,
36 cl::desc(""),
37 cl::Required, cl::sub(GraphDiff));
38
39 static cl::opt
40 GraphDiffKeepGoing("keep-going",
41 cl::desc("Keep going on errors encountered"),
42 cl::sub(GraphDiff), cl::init(false));
43 static cl::alias GraphDiffKeepGoingA("k", cl::aliasopt(GraphDiffKeepGoing),
44 cl::desc("Alias for -keep-going"),
45 cl::sub(GraphDiff));
46 static cl::opt
47 GraphDiffKeepGoing1("keep-going-1",
48 cl::desc("Keep going on errors encountered in trace 1"),
49 cl::sub(GraphDiff), cl::init(false));
50 static cl::alias GraphDiffKeepGoing1A("k1", cl::aliasopt(GraphDiffKeepGoing1),
51 cl::desc("Alias for -keep-going-1"),
52 cl::sub(GraphDiff));
53 static cl::opt
54 GraphDiffKeepGoing2("keep-going-2",
55 cl::desc("Keep going on errors encountered in trace 2"),
56 cl::sub(GraphDiff), cl::init(false));
57 static cl::alias GraphDiffKeepGoing2A("k2", cl::aliasopt(GraphDiffKeepGoing2),
58 cl::desc("Alias for -keep-going-2"),
59 cl::sub(GraphDiff));
60
61 static cl::opt
62 GraphDiffInstrMap("instr-map",
63 cl::desc("binary with the instrumentation map, or "
64 "a separate instrumentation map for graph"),
65 cl::value_desc("binary with xray_instr_map or yaml"),
66 cl::sub(GraphDiff), cl::init(""));
67 static cl::alias GraphDiffInstrMapA("m", cl::aliasopt(GraphDiffInstrMap),
68 cl::desc("Alias for -instr-map"),
69 cl::sub(GraphDiff));
70 static cl::opt
71 GraphDiffInstrMap1("instr-map-1",
72 cl::desc("binary with the instrumentation map, or "
73 "a separate instrumentation map for graph 1"),
74 cl::value_desc("binary with xray_instr_map or yaml"),
75 cl::sub(GraphDiff), cl::init(""));
76 static cl::alias GraphDiffInstrMap1A("m1", cl::aliasopt(GraphDiffInstrMap1),
77 cl::desc("Alias for -instr-map-1"),
78 cl::sub(GraphDiff));
79 static cl::opt
80 GraphDiffInstrMap2("instr-map-2",
81 cl::desc("binary with the instrumentation map, or "
82 "a separate instrumentation map for graph 2"),
83 cl::value_desc("binary with xray_instr_map or yaml"),
84 cl::sub(GraphDiff), cl::init(""));
85 static cl::alias GraphDiffInstrMap2A("m2", cl::aliasopt(GraphDiffInstrMap2),
86 cl::desc("Alias for -instr-map-2"),
87 cl::sub(GraphDiff));
88
89 static cl::opt GraphDiffDeduceSiblingCalls(
90 "deduce-sibling-calls",
91 cl::desc("Deduce sibling calls when unrolling function call stacks"),
92 cl::sub(GraphDiff), cl::init(false));
93 static cl::alias
94 GraphDiffDeduceSiblingCallsA("d", cl::aliasopt(GraphDiffDeduceSiblingCalls),
95 cl::desc("Alias for -deduce-sibling-calls"),
96 cl::sub(GraphDiff));
97 static cl::opt GraphDiffDeduceSiblingCalls1(
98 "deduce-sibling-calls-1",
99 cl::desc("Deduce sibling calls when unrolling function call stacks"),
100 cl::sub(GraphDiff), cl::init(false));
101 static cl::alias GraphDiffDeduceSiblingCalls1A(
102 "d1", cl::aliasopt(GraphDiffDeduceSiblingCalls1),
103 cl::desc("Alias for -deduce-sibling-calls-1"), cl::sub(GraphDiff));
104 static cl::opt GraphDiffDeduceSiblingCalls2(
105 "deduce-sibling-calls-2",
106 cl::desc("Deduce sibling calls when unrolling function call stacks"),
107 cl::sub(GraphDiff), cl::init(false));
108 static cl::alias GraphDiffDeduceSiblingCalls2A(
109 "d2", cl::aliasopt(GraphDiffDeduceSiblingCalls2),
110 cl::desc("Alias for -deduce-sibling-calls-2"), cl::sub(GraphDiff));
111
112 static cl::opt GraphDiffEdgeLabel(
113 "edge-label", cl::desc("Output graphs with edges labeled with this field"),
114 cl::value_desc("field"), cl::sub(GraphDiff),
115 cl::init(GraphRenderer::StatType::NONE),
116 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
117 "Do not label Edges"),
118 clEnumValN(GraphRenderer::StatType::COUNT, "count",
119 "function call counts"),
120 clEnumValN(GraphRenderer::StatType::MIN, "min",
121 "minimum function durations"),
122 clEnumValN(GraphRenderer::StatType::MED, "med",
123 "median function durations"),
124 clEnumValN(GraphRenderer::StatType::PCT90, "90p",
125 "90th percentile durations"),
126 clEnumValN(GraphRenderer::StatType::PCT99, "99p",
127 "99th percentile durations"),
128 clEnumValN(GraphRenderer::StatType::MAX, "max",
129 "maximum function durations"),
130 clEnumValN(GraphRenderer::StatType::SUM, "sum",
131 "sum of call durations")));
132 static cl::alias GraphDiffEdgeLabelA("e", cl::aliasopt(GraphDiffEdgeLabel),
133 cl::desc("Alias for -edge-label"),
134 cl::sub(GraphDiff));
135
136 static cl::opt GraphDiffEdgeColor(
137 "edge-color", cl::desc("Output graphs with edges colored by this field"),
138 cl::value_desc("field"), cl::sub(GraphDiff),
139 cl::init(GraphRenderer::StatType::NONE),
140 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
141 "Do not color Edges"),
142 clEnumValN(GraphRenderer::StatType::COUNT, "count",
143 "function call counts"),
144 clEnumValN(GraphRenderer::StatType::MIN, "min",
145 "minimum function durations"),
146 clEnumValN(GraphRenderer::StatType::MED, "med",
147 "median function durations"),
148 clEnumValN(GraphRenderer::StatType::PCT90, "90p",
149 "90th percentile durations"),
150 clEnumValN(GraphRenderer::StatType::PCT99, "99p",
151 "99th percentile durations"),
152 clEnumValN(GraphRenderer::StatType::MAX, "max",
153 "maximum function durations"),
154 clEnumValN(GraphRenderer::StatType::SUM, "sum",
155 "sum of call durations")));
156 static cl::alias GraphDiffEdgeColorA("c", cl::aliasopt(GraphDiffEdgeColor),
157 cl::desc("Alias for -edge-color"),
158 cl::sub(GraphDiff));
159
160 static cl::opt GraphDiffVertexLabel(
161 "vertex-label",
162 cl::desc("Output graphs with vertices labeled with this field"),
163 cl::value_desc("field"), cl::sub(GraphDiff),
164 cl::init(GraphRenderer::StatType::NONE),
165 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
166 "Do not label Vertices"),
167 clEnumValN(GraphRenderer::StatType::COUNT, "count",
168 "function call counts"),
169 clEnumValN(GraphRenderer::StatType::MIN, "min",
170 "minimum function durations"),
171 clEnumValN(GraphRenderer::StatType::MED, "med",
172 "median function durations"),
173 clEnumValN(GraphRenderer::StatType::PCT90, "90p",
174 "90th percentile durations"),
175 clEnumValN(GraphRenderer::StatType::PCT99, "99p",
176 "99th percentile durations"),
177 clEnumValN(GraphRenderer::StatType::MAX, "max",
178 "maximum function durations"),
179 clEnumValN(GraphRenderer::StatType::SUM, "sum",
180 "sum of call durations")));
181 static cl::alias GraphDiffVertexLabelA("v", cl::aliasopt(GraphDiffVertexLabel),
182 cl::desc("Alias for -vertex-label"),
183 cl::sub(GraphDiff));
184
185 static cl::opt GraphDiffVertexColor(
186 "vertex-color",
187 cl::desc("Output graphs with vertices colored by this field"),
188 cl::value_desc("field"), cl::sub(GraphDiff),
189 cl::init(GraphRenderer::StatType::NONE),
190 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
191 "Do not color Vertices"),
192 clEnumValN(GraphRenderer::StatType::COUNT, "count",
193 "function call counts"),
194 clEnumValN(GraphRenderer::StatType::MIN, "min",
195 "minimum function durations"),
196 clEnumValN(GraphRenderer::StatType::MED, "med",
197 "median function durations"),
198 clEnumValN(GraphRenderer::StatType::PCT90, "90p",
199 "90th percentile durations"),
200 clEnumValN(GraphRenderer::StatType::PCT99, "99p",
201 "99th percentile durations"),
202 clEnumValN(GraphRenderer::StatType::MAX, "max",
203 "maximum function durations"),
204 clEnumValN(GraphRenderer::StatType::SUM, "sum",
205 "sum of call durations")));
206 static cl::alias GraphDiffVertexColorA("b", cl::aliasopt(GraphDiffVertexColor),
207 cl::desc("Alias for -vertex-color"),
208 cl::sub(GraphDiff));
209
210 static cl::opt GraphDiffVertexLabelTrunc(
211 "vertex-label-trun", cl::desc("What length to truncate vertex labels to "),
212 cl::sub(GraphDiff), cl::init(40));
213 static cl::alias
214 GraphDiffVertexLabelTrunc1("t", cl::aliasopt(GraphDiffVertexLabelTrunc),
215 cl::desc("Alias for -vertex-label-trun"),
216 cl::sub(GraphDiff));
217
218 static cl::opt
219 GraphDiffOutput("output", cl::value_desc("Output file"), cl::init("-"),
220 cl::desc("output file; use '-' for stdout"),
221 cl::sub(GraphDiff));
222 static cl::alias GraphDiffOutputA("o", cl::aliasopt(GraphDiffOutput),
223 cl::desc("Alias for -output"),
224 cl::sub(GraphDiff));
225
226 Expected GraphDiffRenderer::Factory::getGraphDiffRenderer() {
227 GraphDiffRenderer R;
228
229 for (int i = 0; i < N; ++i) {
230 const auto &G = this->G[i].get();
231 for (const auto &V : G.vertices()) {
232 const auto &VAttr = V.second;
233 R.G[VAttr.SymbolName].CorrVertexPtr[i] = &V;
234 }
235 for (const auto &E : G.edges()) {
236 auto &EdgeTailID = E.first.first;
237 auto &EdgeHeadID = E.first.second;
238 auto EdgeTailAttrOrErr = G.at(EdgeTailID);
239 auto EdgeHeadAttrOrErr = G.at(EdgeHeadID);
240 if (!EdgeTailAttrOrErr)
241 return EdgeTailAttrOrErr.takeError();
242 if (!EdgeHeadAttrOrErr)
243 return EdgeHeadAttrOrErr.takeError();
244 GraphT::EdgeIdentifier ID{EdgeTailAttrOrErr->SymbolName,
245 EdgeHeadAttrOrErr->SymbolName};
246 R.G[ID].CorrEdgePtr[i] = &E;
247 }
248 }
249
250 return R;
251 }
252 // Returns the Relative change With respect to LeftStat between LeftStat
253 // and RightStat.
254 static double statRelDiff(const GraphDiffRenderer::TimeStat &LeftStat,
255 const GraphDiffRenderer::TimeStat &RightStat,
256 GraphDiffRenderer::StatType T) {
257 double LeftAttr = LeftStat.getDouble(T);
258 double RightAttr = RightStat.getDouble(T);
259
260 return RightAttr / LeftAttr - 1.0;
261 }
262
263 static std::string getColor(const GraphDiffRenderer::GraphT::EdgeValueType &E,
264 const GraphDiffRenderer::GraphT &G, ColorHelper H,
265 GraphDiffRenderer::StatType T) {
266 auto &EdgeAttr = E.second;
267 if (EdgeAttr.CorrEdgePtr[0] == nullptr)
268 return H.getColorString(2.0); // A number greater than 1.0
269 if (EdgeAttr.CorrEdgePtr[1] == nullptr)
270 return H.getColorString(-2.0); // A number less than -1.0
271
272 if (T == GraphDiffRenderer::StatType::NONE)
273 return H.getDefaultColorString();
274
275 const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
276 const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
277
278 double RelDiff = statRelDiff(LeftStat, RightStat, T);
279 double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
280
281 return H.getColorString(CappedRelDiff);
282 }
283
284 static std::string getColor(const GraphDiffRenderer::GraphT::VertexValueType &V,
285 const GraphDiffRenderer::GraphT &G, ColorHelper H,
286 GraphDiffRenderer::StatType T) {
287 auto &VertexAttr = V.second;
288 if (VertexAttr.CorrVertexPtr[0] == nullptr)
289 return H.getColorString(2.0); // A number greater than 1.0
290 if (VertexAttr.CorrVertexPtr[1] == nullptr)
291 return H.getColorString(-2.0); // A number less than -1.0
292
293 if (T == GraphDiffRenderer::StatType::NONE)
294 return H.getDefaultColorString();
295
296 const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
297 const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
298
299 double RelDiff = statRelDiff(LeftStat, RightStat, T);
300 double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
301
302 return H.getColorString(CappedRelDiff);
303 }
304
305 static Twine truncateString(const StringRef &S, size_t n) {
306 return (S.size() > n) ? Twine(S.substr(0, n)) + "..." : Twine(S);
307 }
308
309 template static bool containsNullptr(const T &Collection) {
310 for (const auto &E : Collection)
311 if (E == nullptr)
312 return true;
313 return false;
314 }
315
316 static std::string getLabel(const GraphDiffRenderer::GraphT::EdgeValueType &E,
317 GraphDiffRenderer::StatType EL) {
318 auto &EdgeAttr = E.second;
319 switch (EL) {
320 case GraphDiffRenderer::StatType::NONE:
321 return "";
322 default:
323 if (containsNullptr(EdgeAttr.CorrEdgePtr))
324 return "";
325
326 const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
327 const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
328
329 double RelDiff = statRelDiff(LeftStat, RightStat, EL);
330 return formatv(R"({0:P})", RelDiff);
331 }
332 }
333
334 static std::string getLabel(const GraphDiffRenderer::GraphT::VertexValueType &V,
335 GraphDiffRenderer::StatType VL, int TrunLen) {
336 const auto &VertexId = V.first;
337 const auto &VertexAttr = V.second;
338 switch (VL) {
339 case GraphDiffRenderer::StatType::NONE:
340 return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
341 default:
342 if (containsNullptr(VertexAttr.CorrVertexPtr))
343 return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
344
345 const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
346 const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
347
348 double RelDiff = statRelDiff(LeftStat, RightStat, VL);
349 return formatv(R"({{{0}|{1:P}})", truncateString(VertexId, TrunLen).str(),
350 RelDiff);
351 }
352 }
353
354 static double getLineWidth(const GraphDiffRenderer::GraphT::EdgeValueType &E,
355 GraphDiffRenderer::StatType EL) {
356 auto &EdgeAttr = E.second;
357 switch (EL) {
358 case GraphDiffRenderer::StatType::NONE:
359 return 1.0;
360 default:
361 if (containsNullptr(EdgeAttr.CorrEdgePtr))
362 return 1.0;
363
364 const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
365 const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
366
367 double RelDiff = statRelDiff(LeftStat, RightStat, EL);
368 return (RelDiff > 1.0) ? RelDiff : 1.0;
369 }
370 }
371
372 void GraphDiffRenderer::exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel,
373 StatType EdgeColor,
374 StatType VertexLabel,
375 StatType VertexColor, int TruncLen) {
376 // Get numbering of vertices for dot output.
377 StringMap VertexNo;
378
379 int i = 0;
380 for (const auto &V : G.vertices()) {
381 VertexNo[V.first] = i++;
382 }
383
384 ColorHelper H(ColorHelper::DivergingScheme::PiYG);
385
386 OS << "digraph xrayDiff {\n";
387
388 if (VertexLabel != StatType::NONE)
389 OS << "node [shape=record]\n";
390
391 for (const auto &E : G.edges()) {
392 const auto &HeadId = E.first.first;
393 const auto &TailId = E.first.second;
394 OS << formatv(R"(F{0} -> F{1} [tooltip="{2} -> {3}" label="{4}" )"
395 R"(color="{5}" labelfontcolor="{5}" penwidth={6}])"
396 "\n",
397 VertexNo[HeadId], VertexNo[TailId],
398 (HeadId.equals("")) ? static_cast("F0") : HeadId,
399 TailId, getLabel(E, EdgeLabel), getColor(E, G, H, EdgeColor),
400 getLineWidth(E, EdgeColor));
401 }
402
403 for (const auto &V : G.vertices()) {
404 const auto &VertexId = V.first;
405 if (VertexId.equals("")) {
406 OS << formatv(R"(F{0} [label="F0"])"
407 "\n",
408 VertexNo[VertexId]);
409 continue;
410 }
411 OS << formatv(R"(F{0} [label="{1}" color="{2}"])"
412 "\n",
413 VertexNo[VertexId], getLabel(V, VertexLabel, TruncLen),
414 getColor(V, G, H, VertexColor));
415 }
416
417 OS << "}\n";
418 };
419
420 template static T &ifSpecified(T &A, cl::alias &AA, T &B) {
421 if (A.getPosition() == 0 && AA.getPosition() == 0)
422 return B;
423
424 return A;
425 }
426
427 static CommandRegistration Unused(&GraphDiff, []() -> Error {
428 std::array Factories{
429 {{ifSpecified(GraphDiffKeepGoing1, GraphDiffKeepGoing1A,
430 GraphDiffKeepGoing),
431 ifSpecified(GraphDiffDeduceSiblingCalls1, GraphDiffDeduceSiblingCalls1A,
432 GraphDiffDeduceSiblingCalls),
433 ifSpecified(GraphDiffInstrMap1, GraphDiffInstrMap1A, GraphDiffInstrMap),
434 Trace()},
435 {ifSpecified(GraphDiffKeepGoing2, GraphDiffKeepGoing2A,
436 GraphDiffKeepGoing),
437 ifSpecified(GraphDiffDeduceSiblingCalls2, GraphDiffDeduceSiblingCalls2A,
438 GraphDiffDeduceSiblingCalls),
439 ifSpecified(GraphDiffInstrMap2, GraphDiffInstrMap2A, GraphDiffInstrMap),
440 Trace()}}};
441
442 std::array Inputs{{GraphDiffInput1, GraphDiffInput2}};
443
444 std::array Graphs;
445
446 for (int i = 0; i < 2; i++) {
447 auto TraceOrErr = loadTraceFile(Inputs[i], true);
448 if (!TraceOrErr)
449 return make_error(
450 Twine("Failed Loading Input File '") + Inputs[i] + "'",
451 make_error_code(llvm::errc::invalid_argument));
452 Factories[i].Trace = std::move(*TraceOrErr);
453
454 auto GraphRendererOrErr = Factories[i].getGraphRenderer();
455
456 if (!GraphRendererOrErr)
457 return GraphRendererOrErr.takeError();
458
459 auto GraphRenderer = *GraphRendererOrErr;
460
461 Graphs[i] = GraphRenderer.getGraph();
462 }
463
464 GraphDiffRenderer::Factory DGF(Graphs[0], Graphs[1]);
465
466 auto GDROrErr = DGF.getGraphDiffRenderer();
467 if (!GDROrErr)
468 return GDROrErr.takeError();
469
470 auto &GDR = *GDROrErr;
471
472 std::error_code EC;
473 raw_fd_ostream OS(GraphDiffOutput, EC, sys::fs::OpenFlags::F_Text);
474 if (EC)
475 return make_error(
476 Twine("Cannot open file '") + GraphDiffOutput + "' for writing.", EC);
477
478 GDR.exportGraphAsDOT(OS, GraphDiffEdgeLabel, GraphDiffEdgeColor,
479 GraphDiffVertexLabel, GraphDiffVertexColor,
480 GraphDiffVertexLabelTrunc);
481
482 return Error::success();
483 });
0 //===-- xray-graph-diff.h - XRay Graph Diff Renderer ------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Generate a DOT file to represent the difference between the function call
10 // graph of two differnent traces.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef XRAY_GRAPH_DIFF_H
15 #define XRAY_GRAPH_DIFF_H
16
17 #include "xray-graph.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/XRay/Graph.h"
20
21 namespace llvm {
22 namespace xray {
23
24 // This class creates a graph representing the difference between two
25 // xray-graphs And allows you to print it to a dot file, with optional color
26 // coding.
27 class GraphDiffRenderer {
28 static const int N = 2;
29
30 public:
31 using StatType = GraphRenderer::StatType;
32 using TimeStat = GraphRenderer::TimeStat;
33
34 using GREdgeValueType = GraphRenderer::GraphT::EdgeValueType;
35 using GRVertexValueType = GraphRenderer::GraphT::VertexValueType;
36
37 struct EdgeAttribute {
38 std::array CorrEdgePtr = {};
39 };
40
41 struct VertexAttribute {
42 std::array CorrVertexPtr = {};
43 };
44
45 using GraphT = Graph;
46
47 class Factory {
48 std::array, N> G;
49
50 public:
51 template Factory(Ts &... Args) : G{{Args...}} {};
52
53 Expected getGraphDiffRenderer();
54 };
55
56 private:
57 GraphT G;
58
59 GraphDiffRenderer() = default;
60
61 public:
62 void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
63 StatType EdgeColor = StatType::NONE,
64 StatType VertexLabel = StatType::NONE,
65 StatType VertexColor = StatType::NONE,
66 int TruncLen = 40);
67
68 const GraphT &getGraph() { return G; };
69 };
70 } // namespace xray
71 } // namespace llvm
72
73 #endif
1818
1919 #include "xray-graph.h"
2020 #include "xray-registry.h"
21 #include "llvm/ADT/ArrayRef.h"
2221 #include "llvm/Support/ErrorHandling.h"
2322 #include "llvm/Support/FormatVariadic.h"
2423 #include "llvm/XRay/InstrumentationMap.h"
9796 cl::value_desc("field"), cl::sub(GraphC),
9897 cl::init(GraphRenderer::StatType::NONE),
9998 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
100 "Do not label Edges"),
99 "Do not label Vertices"),
101100 clEnumValN(GraphRenderer::StatType::COUNT, "count",
102101 "function call counts"),
103102 clEnumValN(GraphRenderer::StatType::MIN, "min",
122121 cl::value_desc("field"), cl::sub(GraphC),
123122 cl::init(GraphRenderer::StatType::NONE),
124123 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
125 "Do not label Edges"),
124 "Do not color Edges"),
126125 clEnumValN(GraphRenderer::StatType::COUNT, "count",
127126 "function call counts"),
128127 clEnumValN(GraphRenderer::StatType::MIN, "min",
147146 cl::value_desc("field"), cl::sub(GraphC),
148147 cl::init(GraphRenderer::StatType::NONE),
149148 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
150 "Do not label Edges"),
149 "Do not color vertices"),
151150 clEnumValN(GraphRenderer::StatType::COUNT, "count",
152151 "function call counts"),
153152 clEnumValN(GraphRenderer::StatType::MIN, "min",
209208 auto &ThreadStack = PerThreadFunctionStack[Record.TId];
210209 switch (Record.Type) {
211210 case RecordTypes::ENTER: {
212 if (G.count(Record.FuncId) == 0)
211 if (Record.FuncId != 0 && G.count(Record.FuncId) == 0)
213212 G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId);
214213 ThreadStack.push_back({Record.FuncId, Record.TSC});
215214 break;
311310 // TimeStat element.
312311 static void normalizeTimeStat(GraphRenderer::TimeStat &S,
313312 double CycleFrequency) {
314 S.Min /= CycleFrequency;
315 S.Median /= CycleFrequency;
316 S.Max /= CycleFrequency;
317 S.Sum /= CycleFrequency;
318 S.Pct90 /= CycleFrequency;
319 S.Pct99 /= CycleFrequency;
313 int64_t OldCount = S.Count;
314 S = S / CycleFrequency;
315 S.Count = OldCount;
320316 }
321317
322318 // Normalises the statistics in the graph for a given TSC frequency.
336332
337333 // Returns a string containing the value of statistic field T
338334 std::string
339 GraphRenderer::TimeStat::getAsString(GraphRenderer::StatType T) const {
335 GraphRenderer::TimeStat::getString(GraphRenderer::StatType T) const {
340336 std::string St;
341337 raw_string_ostream S{St};
338 double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median,
339 &TimeStat::Pct90, &TimeStat::Pct99,
340 &TimeStat::Max, &TimeStat::Sum};
342341 switch (T) {
342 case GraphRenderer::StatType::NONE:
343 break;
343344 case GraphRenderer::StatType::COUNT:
344345 S << Count;
345346 break;
346 case GraphRenderer::StatType::MIN:
347 S << Min;
348 break;
349 case GraphRenderer::StatType::MED:
350 S << Median;
351 break;
352 case GraphRenderer::StatType::PCT90:
353 S << Pct90;
354 break;
355 case GraphRenderer::StatType::PCT99:
356 S << Pct99;
357 break;
358 case GraphRenderer::StatType::MAX:
359 S << Max;
360 break;
361 case GraphRenderer::StatType::SUM:
362 S << Sum;
363 break;
364 case GraphRenderer::StatType::NONE:
347 default:
348 S << (*this).*
349 DoubleStatPtrs[static_cast(T) -
350 static_cast(GraphRenderer::StatType::MIN)];
365351 break;
366352 }
367353 return S.str();
369355
370356 // Returns the quotient between the property T of this and another TimeStat as
371357 // a double
372 double GraphRenderer::TimeStat::compare(StatType T, const TimeStat &O) const {
358 double GraphRenderer::TimeStat::getDouble(StatType T) const {
373359 double retval = 0;
360 double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median,
361 &TimeStat::Pct90, &TimeStat::Pct99,
362 &TimeStat::Max, &TimeStat::Sum};
374363 switch (T) {
375 case GraphRenderer::StatType::COUNT:
376 retval = static_cast(Count) / static_cast(O.Count);
377 break;
378 case GraphRenderer::StatType::MIN:
379 retval = Min / O.Min;
380 break;
381 case GraphRenderer::StatType::MED:
382 retval = Median / O.Median;
383 break;
384 case GraphRenderer::StatType::PCT90:
385 retval = Pct90 / O.Pct90;
386 break;
387 case GraphRenderer::StatType::PCT99:
388 retval = Pct99 / O.Pct99;
389 break;
390 case GraphRenderer::StatType::MAX:
391 retval = Max / O.Max;
392 break;
393 case GraphRenderer::StatType::SUM:
394 retval = Sum / O.Sum;
395 break;
396364 case GraphRenderer::StatType::NONE:
397365 retval = 0.0;
398366 break;
399 }
400 return std::sqrt(
401 retval); // the square root here provides more dynamic contrast for
402 // low runtime edges, giving better separation and
403 // coloring lower down the call stack.
367 case GraphRenderer::StatType::COUNT:
368 retval = static_cast(Count);
369 break;
370 default:
371 retval =
372 (*this).*DoubleStatPtrs[static_cast(T) -
373 static_cast(GraphRenderer::StatType::MIN)];
374 break;
375 }
376 return retval;
404377 }
405378
406379 // Outputs a DOT format version of the Graph embedded in the GraphRenderer
409382 // annotations.
410383 //
411384 // FIXME: output more information, better presented.
412 void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
413 StatType ET, StatType EC, StatType VT,
414 StatType VC) {
415 G.GraphEdgeMax = {};
416 G.GraphVertexMax = {};
417 calculateEdgeStatistics();
418 calculateVertexStatistics();
419
420 if (H.CycleFrequency)
421 normalizeStatistics(H.CycleFrequency);
422
385 void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, StatType ET, StatType EC,
386 StatType VT, StatType VC) {
423387 OS << "digraph xray {\n";
424388
425389 if (VT != StatType::NONE)
428392 for (const auto &E : G.edges()) {
429393 const auto &S = E.second.S;
430394 OS << "F" << E.first.first << " -> "
431 << "F" << E.first.second << " [label=\"" << S.getAsString(ET) << "\"";
395 << "F" << E.first.second << " [label=\"" << S.getString(ET) << "\"";
432396 if (EC != StatType::NONE)
433 OS << " color=\"" << CHelper.getColorString(S.compare(EC, G.GraphEdgeMax))
397 OS << " color=\""
398 << CHelper.getColorString(
399 std::sqrt(S.getDouble(EC) / G.GraphEdgeMax.getDouble(EC)))
434400 << "\"";
435401 OS << "];\n";
436402 }
443409 << (VA.SymbolName.size() > 40 ? VA.SymbolName.substr(0, 40) + "..."
444410 : VA.SymbolName);
445411 if (VT != StatType::NONE)
446 OS << "|" << VA.S.getAsString(VT) << "}\"";
412 OS << "|" << VA.S.getString(VT) << "}\"";
447413 else
448414 OS << "\"";
449415 if (VC != StatType::NONE)
450 OS << " color=\"" << CHelper.getColorString(VA.S.compare(VC, G.GraphVertexMax))
416 OS << " color=\""
417 << CHelper.getColorString(
418 std::sqrt(VA.S.getDouble(VC) / G.GraphVertexMax.getDouble(VC)))
451419 << "\"";
452420 OS << "];\n";
453421 }
454422 OS << "}\n";
455423 }
456424
457 // Here we register and implement the llvm-xray graph subcommand.
458 // The bulk of this code reads in the options, opens the required files, uses
459 // those files to create a context for analysing the xray trace, then there is a
460 // short loop which actually analyses the trace, generates the graph and then
461 // outputs it as a DOT.
462 //
463 // FIXME: include additional filtering and annalysis passes to provide more
464 // specific useful information.
465 static CommandRegistration Unused(&GraphC, []() -> Error {
425 Expected GraphRenderer::Factory::getGraphRenderer() {
466426 InstrumentationMap Map;
467427 if (!GraphInstrMap.empty()) {
468428 auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap);
476436 }
477437
478438 const auto &FunctionAddresses = Map.getFunctionAddresses();
439
479440 symbolize::LLVMSymbolizer::Options Opts(
480441 symbolize::FunctionNameKind::LinkageName, true, true, false, "");
481442 symbolize::LLVMSymbolizer Symbolizer(Opts);
482 llvm::xray::FuncIdConversionHelper FuncIdHelper(GraphInstrMap, Symbolizer,
443 const auto &Header = Trace.getFileHeader();
444
445 llvm::xray::FuncIdConversionHelper FuncIdHelper(InstrMap, Symbolizer,
483446 FunctionAddresses);
484 xray::GraphRenderer GR(FuncIdHelper, GraphDeduceSiblingCalls);
485 std::error_code EC;
486 raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text);
487 if (EC)
488 return make_error(
489 Twine("Cannot open file '") + GraphOutput + "' for writing.", EC);
490
491 auto TraceOrErr = loadTraceFile(GraphInput, true);
492 if (!TraceOrErr)
493 return joinErrors(
494 make_error(Twine("Failed loading input file '") +
495 GraphInput + "'",
496 make_error_code(llvm::errc::invalid_argument)),
497 TraceOrErr.takeError());
498
499 auto &Trace = *TraceOrErr;
500 const auto &Header = Trace.getFileHeader();
501
502 // Here we generate the call graph from entries we find in the trace.
447
448 xray::GraphRenderer GR(FuncIdHelper, DeduceSiblingCalls);
503449 for (const auto &Record : Trace) {
504450 auto E = GR.accountRecord(Record);
505451 if (!E)
522468 handleAllErrors(std::move(E),
523469 [&](const ErrorInfoBase &E) { E.log(errs()); });
524470 }
525 GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType,
526 GraphVertexLabel, GraphVertexColorType);
471
472 GR.G.GraphEdgeMax = {};
473 GR.G.GraphVertexMax = {};
474 GR.calculateEdgeStatistics();
475 GR.calculateVertexStatistics();
476
477 if (Header.CycleFrequency)
478 GR.normalizeStatistics(Header.CycleFrequency);
479
480 return GR;
481 }
482
483 // Here we register and implement the llvm-xray graph subcommand.
484 // The bulk of this code reads in the options, opens the required files, uses
485 // those files to create a context for analysing the xray trace, then there is a
486 // short loop which actually analyses the trace, generates the graph and then
487 // outputs it as a DOT.
488 //
489 // FIXME: include additional filtering and annalysis passes to provide more
490 // specific useful information.
491 static CommandRegistration Unused(&GraphC, []() -> Error {
492 GraphRenderer::Factory F;
493
494 F.KeepGoing = GraphKeepGoing;
495 F.DeduceSiblingCalls = GraphDeduceSiblingCalls;
496 F.InstrMap = GraphInstrMap;
497
498 auto TraceOrErr = loadTraceFile(GraphInput, true);
499
500 if (!TraceOrErr)
501 return make_error(
502 Twine("Failed loading input file '") + GraphInput + "'",
503 make_error_code(llvm::errc::invalid_argument));
504
505 F.Trace = std::move(*TraceOrErr);
506 auto GROrError = F.getGraphRenderer();
507 if (!GROrError)
508 return GROrError.takeError();
509 auto &GR = *GROrError;
510
511 std::error_code EC;
512 raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text);
513 if (EC)
514 return make_error(
515 Twine("Cannot open file '") + GraphOutput + "' for writing.", EC);
516
517 GR.exportGraphAsDOT(OS, GraphEdgeLabel, GraphEdgeColorType, GraphVertexLabel,
518 GraphVertexColorType);
527519 return Error::success();
528520 });
4040
4141 /// An inner struct for common timing statistics information
4242 struct TimeStat {
43 uint64_t Count = 0;
44 double Min = 0;
45 double Median = 0;
46 double Pct90 = 0;
47 double Pct99 = 0;
48 double Max = 0;
49 double Sum = 0;
50 std::string getAsString(StatType T) const;
51 double compare(StatType T, const TimeStat &Other) const;
52 };
53 typedef uint64_t TimestampT;
43 int64_t Count;
44 double Min;
45 double Median;
46 double Pct90;
47 double Pct99;
48 double Max;
49 double Sum;
50
51 std::string getString(StatType T) const;
52 double getDouble(StatType T) const;
53 };
54 using TimestampT = uint64_t;
5455
5556 /// An inner struct for storing edge attributes for our graph. Here the
5657 /// attributes are mainly function call statistics.
6768 /// FIXME: Store more attributes based on instrumentation map.
6869 struct FunctionStats {
6970 std::string SymbolName;
70 TimeStat S;
71 TimeStat S = {};
7172 };
7273
7374 struct FunctionAttr {
7576 uint64_t TSC;
7677 };
7778
78 typedef SmallVector FunctionStack;
79
80 typedef DenseMap
81 PerThreadFunctionStackMap;
79 using FunctionStack = SmallVector;
80
81 using PerThreadFunctionStackMap =
82 DenseMap;
8283
8384 class GraphT : public Graph {
8485 public:
8788 };
8889
8990 GraphT G;
90 typedef typename decltype(G)::VertexIdentifier VertexIdentifier;
91 typedef typename decltype(G)::EdgeIdentifier EdgeIdentifier;
91 using VertexIdentifier = typename decltype(G)::VertexIdentifier;
92 using EdgeIdentifier = decltype(G)::EdgeIdentifier;
9293
9394 /// Use a Map to store the Function stack for each thread whilst building the
9495 /// graph.
9798 PerThreadFunctionStackMap PerThreadFunctionStack;
9899
99100 /// Usefull object for getting human readable Symbol Names.
100 const FuncIdConversionHelper &FuncIdHelper;
101 FuncIdConversionHelper FuncIdHelper;
101102 bool DeduceSiblingCalls = false;
102103 TimestampT CurrentMaxTSC = 0;
103104
142143 return PerThreadFunctionStack;
143144 }
144145
146 class Factory {
147 public:
148 bool KeepGoing;
149 bool DeduceSiblingCalls;
150 std::string InstrMap;
151 Trace Trace;
152 Expected getGraphRenderer();
153 };
154
145155 /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
146156 /// \p T
147 void exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
148 StatType EdgeLabel = StatType::NONE,
157 void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
149158 StatType EdgeColor = StatType::NONE,
150159 StatType VertexLabel = StatType::NONE,
151160 StatType VertexColor = StatType::NONE);
152161
153162 /// Get a reference to the internal graph.
154 const GraphT &getGraph() {
155 calculateEdgeStatistics();
156 calculateVertexStatistics();
157 return G;
158 }
163 const GraphT &getGraph() { return G; }
159164 };
160 }
161 }
165
166 /// Vector Sum of TimeStats
167 inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A,
168 const GraphRenderer::TimeStat &B) {
169 return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median,
170 A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max,
171 A.Sum + B.Sum};
172 }
173
174 /// Vector Difference of Timestats
175 inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A,
176 const GraphRenderer::TimeStat &B) {
177
178 return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median,
179 A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max,
180 A.Sum - B.Sum};
181 }
182
183 /// Scalar Diference of TimeStat and double
184 inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
185 double B) {
186
187 return {static_cast(A.Count / B),
188 A.Min / B,
189 A.Median / B,
190 A.Pct90 / B,
191 A.Pct99 / B,
192 A.Max / B,
193 A.Sum / B};
194 }
195
196 /// Scalar product of TimeStat and Double
197 inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
198 double B) {
199 return {static_cast(A.Count * B),
200 A.Min * B,
201 A.Median * B,
202 A.Pct90 * B,
203 A.Pct99 * B,
204 A.Max * B,
205 A.Sum * B};
206 }
207
208 /// Scalar product of double TimeStat
209 inline GraphRenderer::TimeStat operator*(double A,
210 const GraphRenderer::TimeStat &B) {
211 return B * A;
212 }
213
214 /// Hadamard Product of TimeStats
215 inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
216 const GraphRenderer::TimeStat &B) {
217 return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
218 A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
219 A.Sum * B.Sum};
220 }
221
222 /// Hadamard Division of TimeStats
223 inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
224 const GraphRenderer::TimeStat &B) {
225 return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
226 A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
227 A.Sum * B.Sum};
228 }
229 } // namespace xray
230 } // namespace llvm
162231
163232 #endif // XRAY_GRAPH_H