Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
David Goulet
Tor
Commits
494dea70
Commit
494dea70
authored
Aug 15, 2015
by
Nick Mathewson
🥄
Browse files
Merge branch 'analyze_cg_more'
parents
98b2a3b3
bb466305
Changes
2
Hide whitespace changes
Inline
Side-by-side
scripts/maint/analyze_callgraph.py
View file @
494dea70
...
...
@@ -13,7 +13,7 @@ class Parser:
def
enter_func
(
self
,
name
):
if
self
.
infunc
and
not
self
.
extern
:
self
.
calls
.
setdefault
(
self
.
infunc
,
set
()).
update
(
self
.
calledfns
)
self
.
calledfns
=
set
()
self
.
infunc
=
name
self
.
extern
=
False
...
...
@@ -23,7 +23,7 @@ class Parser:
self
.
extern
=
False
self
.
calledfns
=
set
()
for
line
in
inp
:
m
=
re
.
match
(
r
"Call graph node for function: '([^']+)'"
,
line
)
m
=
re
.
match
(
r
"Call graph node for function: '([^']+)'"
,
line
)
if
m
:
self
.
enter_func
(
m
.
group
(
1
))
continue
...
...
@@ -42,18 +42,28 @@ class Parser:
def
transitive_closure
(
g
):
passno
=
0
changed
=
True
g
=
copy
.
deepcopy
(
g
)
import
random
while
changed
:
passno
+=
1
changed
=
False
print
"X"
for
k
in
g
.
keys
():
keys
=
g
.
keys
()
idx
=
0
for
k
in
keys
:
idx
+=
1
print
"Pass %d/?: %d/%d
\r
"
%
(
passno
,
idx
,
len
(
keys
)),
sys
.
stdout
.
flush
()
newset
=
g
[
k
].
copy
()
for
fn
in
g
[
k
]:
newset
.
update
(
g
.
get
(
fn
,
set
()))
if
len
(
newset
)
!=
len
(
g
[
k
]):
g
[
k
].
update
(
newset
)
changed
=
True
print
return
g
def
strongly_connected_components
(
g
):
...
...
@@ -96,22 +106,114 @@ def strongly_connected_components(g):
return
all_sccs
def
biggest_component
(
sccs
):
return
max
(
len
(
c
)
for
c
in
sccs
)
def
connection_bottlenecks
(
callgraph
):
callers
=
{}
for
fn
in
callgraph
:
for
fn2
in
callgraph
[
fn
]:
callers
.
setdefault
(
fn2
,
set
()).
add
(
fn
)
components
=
strongly_connected_components
(
callgraph
)
components
.
sort
(
key
=
len
)
big_component_fns
=
components
[
-
1
]
size
=
len
(
big_component_fns
)
function_bottlenecks
=
fn_results
=
[]
total
=
len
(
big_component_fns
)
idx
=
0
for
fn
in
big_component_fns
:
idx
+=
1
print
"Pass 1/3: %d/%d
\r
"
%
(
idx
,
total
),
sys
.
stdout
.
flush
()
cg2
=
copy
.
deepcopy
(
callgraph
)
del
cg2
[
fn
]
fn_results
.
append
(
(
size
-
biggest_component
(
strongly_connected_components
(
cg2
)),
fn
)
)
print
bcf_set
=
set
(
big_component_fns
)
call_bottlenecks
=
fn_results
=
[]
result_set
=
set
()
total
=
len
(
big_component_fns
)
idx
=
0
for
fn
in
big_component_fns
:
fn_callers
=
callers
[
fn
].
intersection
(
bcf_set
)
idx
+=
1
if
len
(
fn_callers
)
!=
1
:
continue
print
"Pass 2/3: %d/%d
\r
"
%
(
idx
,
total
),
sys
.
stdout
.
flush
()
caller
=
fn_callers
.
pop
()
assert
len
(
fn_callers
)
==
0
cg2
=
copy
.
deepcopy
(
callgraph
)
cg2
[
caller
].
remove
(
fn
)
fn_results
.
append
(
(
size
-
biggest_component
(
strongly_connected_components
(
cg2
)),
fn
,
"called by"
,
caller
)
)
result_set
.
add
(
(
caller
,
fn
)
)
print
total
=
len
(
big_component_fns
)
idx
=
0
for
fn
in
big_component_fns
:
fn_calls
=
callgraph
[
fn
].
intersection
(
bcf_set
)
idx
+=
1
if
len
(
fn_calls
)
!=
1
:
continue
print
"Pass 3/3: %d/%d
\r
"
%
(
idx
,
total
),
sys
.
stdout
.
flush
()
callee
=
fn_calls
.
pop
()
if
(
fn
,
callee
)
in
result_set
:
continue
assert
len
(
fn_calls
)
==
0
cg2
=
copy
.
deepcopy
(
callgraph
)
cg2
[
fn
].
remove
(
callee
)
fn_results
.
append
(
(
size
-
biggest_component
(
strongly_connected_components
(
cg2
)),
callee
,
"called by"
,
fn
)
)
print
return
(
function_bottlenecks
,
call_bottlenecks
)
if
__name__
==
'__main__'
:
p
=
Parser
()
for
fname
in
sys
.
argv
[
1
:]:
with
open
(
fname
,
'r'
)
as
f
:
p
.
parse_callgraph_file
(
f
)
sys
.
stdout
.
flush
print
"Building callgraph"
callgraph
=
p
.
extract_callgraph
()
print
"Finding strongly connected components"
sccs
=
strongly_connected_components
(
callgraph
)
print
"Finding the transitive closure of the callgraph.."
closure
=
transitive_closure
(
callgraph
)
print
"Finding bottlenecks..."
bottlenecks
=
connection_bottlenecks
(
callgraph
)
data
=
{
'callgraph'
:
callgraph
,
'sccs'
:
sccs
,
'closure'
:
closure
,
'bottlenecks'
:
bottlenecks
}
with
open
(
'callgraph.pkl'
,
'w'
)
as
f
:
cPickle
.
dump
(
callgraph
,
f
)
cPickle
.
dump
(
data
,
f
)
with
open
(
'callgraph_closure.pkl'
,
'w'
)
as
f
:
cPickle
.
dump
(
closure
,
f
)
with
open
(
'callgraph_sccs.pkl'
,
'w'
)
as
f
:
cPickle
.
dump
(
sccs
,
f
)
scripts/maint/display_callgraph.py
View file @
494dea70
...
...
@@ -2,9 +2,12 @@
import
cPickle
callgraph
=
cPickle
.
load
(
open
(
"callgraph.pkl"
))
closure
=
cPickle
.
load
(
open
(
"callgraph_closure.pkl"
))
sccs
=
cPickle
.
load
(
open
(
"callgraph_sccs.pkl"
))
data
=
cPickle
.
load
(
open
(
"callgraph.pkl"
))
callgraph
=
data
[
'callgraph'
]
closure
=
data
[
'closure'
]
sccs
=
data
[
'sccs'
]
fn_bottle
,
call_bottle
=
data
[
'bottlenecks'
]
for
n_reachable
,
fn
in
sorted
(
list
((
len
(
r
),
fn
)
for
fn
,
r
in
closure
.
iteritems
())):
print
"%s can reach %s other functions."
%
(
fn
,
n_reachable
)
...
...
@@ -13,10 +16,24 @@ for n_reachable, fn in sorted(list((len(r), fn) for fn, r in closure.iteritems()
c
=
[
(
len
(
component
),
component
)
for
component
in
sccs
]
c
.
sort
()
print
"
\n
================================"
for
n
,
component
in
c
:
if
n
<
2
:
continue
print
n
,
component
print
"Strongly connected component of size %d:"
%
n
print
component
print
"
\n
================================"
print
"====== Number of functions pulled into blob, by function in blob."
fn_bottle
.
sort
()
for
n
,
fn
in
fn_bottle
[
-
30
:]:
print
"%3d: %s"
%
(
n
,
fn
)
print
"====== Number of functions pulled into blob, by call in blob."
call_bottle
.
sort
()
for
n
,
fn1
,
_
,
fn2
in
call_bottle
[
-
30
:]:
print
"%3d: %s -> %s "
%
(
n
,
fn2
,
fn1
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment