notes
This commit is contained in:
parent
c0d03886cb
commit
331e1cd619
86
srcxray.py
86
srcxray.py
|
@ -67,7 +67,7 @@ ignores = ('aligned unlikely typeof u32 '
|
||||||
'current_user_ns spin_lock_irq spin_unlock_irq prepare_creds '
|
'current_user_ns spin_lock_irq spin_unlock_irq prepare_creds '
|
||||||
'tasklist_lock commit_creds read_lock read_unlock SIGKILL SIGSTOP abort_creds fd_install '
|
'tasklist_lock commit_creds read_lock read_unlock SIGKILL SIGSTOP abort_creds fd_install '
|
||||||
'real_mount FMODE_WRITE tv_nsec putname '
|
'real_mount FMODE_WRITE tv_nsec putname '
|
||||||
).split()
|
).split() # TODO: move to file
|
||||||
|
|
||||||
|
|
||||||
level_limit = 10
|
level_limit = 10
|
||||||
|
@ -81,6 +81,7 @@ files = collections.defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
def print_limited(a, out=None):
|
def print_limited(a, out=None):
|
||||||
|
# exits when reaches limit of printed lines
|
||||||
out = out if out else sys.stdout
|
out = out if out else sys.stdout
|
||||||
out.write(str(a) + '\n')
|
out.write(str(a) + '\n')
|
||||||
global n
|
global n
|
||||||
|
@ -92,6 +93,7 @@ def print_limited(a, out=None):
|
||||||
|
|
||||||
|
|
||||||
def log(*args, **kwargs):
|
def log(*args, **kwargs):
|
||||||
|
# log with context function
|
||||||
if not verbose:
|
if not verbose:
|
||||||
return
|
return
|
||||||
s = str(*args).rstrip()
|
s = str(*args).rstrip()
|
||||||
|
@ -102,11 +104,15 @@ def log(*args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def popen(p):
|
def popen(p):
|
||||||
|
# shortcut for reading output of subcommand
|
||||||
log(p)
|
log(p)
|
||||||
return check_output(p, shell=True).decode('utf-8').splitlines()
|
return check_output(p, shell=True).decode('utf-8').splitlines()
|
||||||
|
|
||||||
|
|
||||||
def extract_referrer(line):
|
def extract_referrer(line):
|
||||||
|
# Extract referrer function from oupput of
|
||||||
|
# git grep --show-function.
|
||||||
|
# With quirks for linux kernel
|
||||||
line = re.sub(r'__ro_after_init', '', line)
|
line = re.sub(r'__ro_after_init', '', line)
|
||||||
line = re.sub(r'FNAME\((\w+)\)', r'\1', line)
|
line = re.sub(r'FNAME\((\w+)\)', r'\1', line)
|
||||||
line = re.sub(r'.*TRACE_EVENT.*', '', line)
|
line = re.sub(r'.*TRACE_EVENT.*', '', line)
|
||||||
|
@ -122,6 +128,7 @@ def extract_referrer(line):
|
||||||
|
|
||||||
|
|
||||||
def extract_referrer_test():
|
def extract_referrer_test():
|
||||||
|
# unittest of extract_referrer
|
||||||
passed = 0
|
passed = 0
|
||||||
for a in {
|
for a in {
|
||||||
"f=1=good2()",
|
"f=1=good2()",
|
||||||
|
@ -147,6 +154,10 @@ def extract_referrer_test():
|
||||||
|
|
||||||
|
|
||||||
def func_referrers_git_grep(name):
|
def func_referrers_git_grep(name):
|
||||||
|
# Subfunction for searching referrers with
|
||||||
|
# git grep --show-function.
|
||||||
|
# Works slowly.
|
||||||
|
# Obsoleted by doxygen_xml.
|
||||||
res = list()
|
res = list()
|
||||||
r = None
|
r = None
|
||||||
for line in popen(r'git grep --threads 1 --no-index --word-regexp '
|
for line in popen(r'git grep --threads 1 --no-index --word-regexp '
|
||||||
|
@ -179,6 +190,9 @@ cscope_warned = False
|
||||||
|
|
||||||
|
|
||||||
def func_referrers_cscope(name):
|
def func_referrers_cscope(name):
|
||||||
|
# Subfunction for searching referrers with cscope.
|
||||||
|
# Works fast.
|
||||||
|
# Obsoleted by doxygen_xml.
|
||||||
global cscope_warned
|
global cscope_warned
|
||||||
if not os.path.isfile('cscope.out'):
|
if not os.path.isfile('cscope.out'):
|
||||||
if not cscope_warned:
|
if not cscope_warned:
|
||||||
|
@ -201,14 +215,11 @@ def func_referrers_cscope(name):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def func_referrers_all(name):
|
|
||||||
return list(dict.fromkeys(func_referrers_git_grep(name) + func_referrers_cscope(name)))
|
|
||||||
|
|
||||||
|
|
||||||
def referrers_tree(name, referrer=None, printed=None, level=0):
|
def referrers_tree(name, referrer=None, printed=None, level=0):
|
||||||
'''
|
'''
|
||||||
Arg: <identifier>
|
Arg: <identifier> - prints text referrers tree.
|
||||||
Ex: nfs_root_data
|
Ex: nfs_root_data
|
||||||
|
Obsoleted by doxygen_xml.
|
||||||
'''
|
'''
|
||||||
if not referrer:
|
if not referrer:
|
||||||
if os.path.isfile('cscope.out'):
|
if os.path.isfile('cscope.out'):
|
||||||
|
@ -239,16 +250,17 @@ def referrers_tree(name, referrer=None, printed=None, level=0):
|
||||||
|
|
||||||
def referrers(name):
|
def referrers(name):
|
||||||
'''
|
'''
|
||||||
Arg: <identifier>
|
Arg: <identifier> - simply greps referrers of a symbol
|
||||||
Ex: nfs_root_data
|
Ex: nfs_root_data
|
||||||
|
Prefer to use doxygen_xml.
|
||||||
'''
|
'''
|
||||||
# for a in func_referrers_git_grep(name):
|
|
||||||
# print("%s:%s: %s"%(a[0],a[1],a[2]))
|
|
||||||
print(' '.join([a[2] for a in func_referrers_git_grep(name)]))
|
print(' '.join([a[2] for a in func_referrers_git_grep(name)]))
|
||||||
|
|
||||||
|
|
||||||
def referrers_dep(name, referrer=None, printed=None, level=0):
|
def referrers_dep(name, referrer=None, printed=None, level=0):
|
||||||
# Arg: <identifier>
|
# Arg: <identifier> - prints referrers tree in compact format of
|
||||||
|
# dependency of make
|
||||||
|
# Obsoleted by doxygen_xml.
|
||||||
if not referrer:
|
if not referrer:
|
||||||
if os.path.isfile('cscope.out'):
|
if os.path.isfile('cscope.out'):
|
||||||
referrer = func_referrers_cscope
|
referrer = func_referrers_cscope
|
||||||
|
@ -278,8 +290,9 @@ def referrers_dep(name, referrer=None, printed=None, level=0):
|
||||||
|
|
||||||
def call_tree(node, printed=None, level=0):
|
def call_tree(node, printed=None, level=0):
|
||||||
'''
|
'''
|
||||||
Arg: <identifier>
|
Arg: <identifier> - prints call tree of a function
|
||||||
Ex: start_kernel
|
Ex: start_kernel
|
||||||
|
Obsoleted by doxygen_xml.
|
||||||
'''
|
'''
|
||||||
if not os.path.isfile('cscope.out'):
|
if not os.path.isfile('cscope.out'):
|
||||||
print("Please run: cscope -Rcbk", file=sys.stderr)
|
print("Please run: cscope -Rcbk", file=sys.stderr)
|
||||||
|
@ -308,6 +321,8 @@ def call_tree(node, printed=None, level=0):
|
||||||
|
|
||||||
|
|
||||||
def call_dep(node, printed=None, level=0):
|
def call_dep(node, printed=None, level=0):
|
||||||
|
# prints call tree in compact format of dependency of make
|
||||||
|
# Obsoleted by doxygen_xml.
|
||||||
if not os.path.isfile('cscope.out'):
|
if not os.path.isfile('cscope.out'):
|
||||||
print("Please run: cscope -Rcbk", file=sys.stderr)
|
print("Please run: cscope -Rcbk", file=sys.stderr)
|
||||||
return False
|
return False
|
||||||
|
@ -334,6 +349,7 @@ def call_dep(node, printed=None, level=0):
|
||||||
|
|
||||||
|
|
||||||
def my_graph(name=None):
|
def my_graph(name=None):
|
||||||
|
# common subfunction
|
||||||
g = nx.DiGraph(name=name)
|
g = nx.DiGraph(name=name)
|
||||||
# g.graph.update({'node': {'shape': 'none', 'fontsize': 50}})
|
# g.graph.update({'node': {'shape': 'none', 'fontsize': 50}})
|
||||||
# g.graph.update({'rankdir': 'LR', 'nodesep': 0, })
|
# g.graph.update({'rankdir': 'LR', 'nodesep': 0, })
|
||||||
|
@ -354,7 +370,9 @@ def reduce_graph(g, m=None):
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
|
||||||
def includes(a):
|
def includes(sym):
|
||||||
|
# subfunction, used in syscalls
|
||||||
|
# extracts include files of a symbol
|
||||||
res = []
|
res = []
|
||||||
# log(a)
|
# log(a)
|
||||||
for a in popen('man -s 2 %s 2> /dev/null |'
|
for a in popen('man -s 2 %s 2> /dev/null |'
|
||||||
|
@ -376,12 +394,12 @@ def includes(a):
|
||||||
if res and len(res) > 1:
|
if res and len(res) > 1:
|
||||||
r = set()
|
r = set()
|
||||||
for f in res:
|
for f in res:
|
||||||
# log('grep " %s \+\(" --include "%s" -r /usr/include/'%(a, f))
|
# log('grep " %s \+\(" --include "%s" -r /usr/include/'%(sym, f))
|
||||||
# log(os.system(
|
# log(os.system(
|
||||||
# 'grep -w "%s" --include "%s" -r /usr/include/'%(a, f)))
|
# 'grep -w "%s" --include "%s" -r /usr/include/'%(sym, f)))
|
||||||
if 0 != os.system(
|
if 0 != os.system(
|
||||||
'grep " %s *(" --include "%s" -r /usr/include/ -q'
|
'grep " %s *(" --include "%s" -r /usr/include/ -q'
|
||||||
% (a, os.path.basename(f))):
|
% (sym, os.path.basename(f))):
|
||||||
r.add(f)
|
r.add(f)
|
||||||
res = res.difference(r)
|
res = res.difference(r)
|
||||||
log(res)
|
log(res)
|
||||||
|
@ -389,6 +407,11 @@ def includes(a):
|
||||||
|
|
||||||
|
|
||||||
def syscalls():
|
def syscalls():
|
||||||
|
# Experimental function for exporting syscalls info
|
||||||
|
# from various sources.
|
||||||
|
# Used in creation of
|
||||||
|
# https://en.wikibooks.org/wiki/The_Linux_Kernel/Syscalls
|
||||||
|
# Ex: srcxray.py "write_dot(syscalls(), 'syscalls.dot')"
|
||||||
sc = my_graph('syscalls')
|
sc = my_graph('syscalls')
|
||||||
inc = 'includes.list'
|
inc = 'includes.list'
|
||||||
if not os.path.isfile(inc):
|
if not os.path.isfile(inc):
|
||||||
|
@ -454,20 +477,9 @@ def syscalls():
|
||||||
return sc
|
return sc
|
||||||
|
|
||||||
|
|
||||||
# DiGraph
|
|
||||||
# write_dot to_agraph AGraph
|
|
||||||
# agwrite
|
|
||||||
# srcxray.py 'write_dot(syscalls(), "syscalls.dot")'
|
|
||||||
# write_graphml
|
|
||||||
# srcxray.py "most_used(read_dot('a.dot'))"
|
|
||||||
# srcxray.py "digraph_print(read_dot('a.dot'))"
|
|
||||||
# srcxray.py "write_dot(reduce_graph(read_dot('no-loops.dot')),'reduced.dot')"
|
|
||||||
# a=sys_clone;srcxray.py "write_dot(rank_couples(reduce_graph(remove_loops(read_dot('$a.dot')))),'$a.dot')"
|
|
||||||
# srcxray.py "pprint(most_used(read_dot('a.dot')))"
|
|
||||||
# srcxray.py "write_dot(add_rank('reduced.dot'), 'ranked.dot')"
|
|
||||||
# srcxray.py "write_dot(remove_loops(read_dot('reduced.dot')), 'no-loops.dot')"
|
|
||||||
|
|
||||||
def cleanup(a):
|
def cleanup(a):
|
||||||
|
# cleanups graph file
|
||||||
|
# wrapper for remove_nodes_from
|
||||||
log('')
|
log('')
|
||||||
g = to_dg(a)
|
g = to_dg(a)
|
||||||
print(dg.number_of_edges())
|
print(dg.number_of_edges())
|
||||||
|
@ -480,15 +492,7 @@ def sort_dict(d):
|
||||||
return [a for a, b in sorted(d.items(), key=lambda k: k[1], reverse=True)]
|
return [a for a, b in sorted(d.items(), key=lambda k: k[1], reverse=True)]
|
||||||
|
|
||||||
|
|
||||||
def most_used(dg, ins=10, outs=10):
|
def starts(dg): # roots of trees in a graph
|
||||||
# return {a: b for a, b in sorted(dg.in_degree, key=lambda k: k[1]) if b > 1 and}
|
|
||||||
# return [(x, dg.in_degree(x), dg.out_degree(x))
|
|
||||||
return [x
|
|
||||||
for x in dg.nodes()
|
|
||||||
if dg.in_degree(x) >= ins and dg.out_degree(x) >= outs]
|
|
||||||
|
|
||||||
|
|
||||||
def starts(dg): # roots
|
|
||||||
return {n: dg.out_degree(n) for (n, d) in dg.in_degree if not d}
|
return {n: dg.out_degree(n) for (n, d) in dg.in_degree if not d}
|
||||||
|
|
||||||
|
|
||||||
|
@ -559,6 +563,7 @@ def digraph_tree(dg, starts=None, ignores=ignores):
|
||||||
def digraph_print(dg, starts=None, dst_fn=None, sort=False):
|
def digraph_print(dg, starts=None, dst_fn=None, sort=False):
|
||||||
'''
|
'''
|
||||||
Arg: <graph> - print graphs as text tree
|
Arg: <graph> - print graphs as text tree
|
||||||
|
Ex2: \"digraph_print(read_dot('a.dot'))\"
|
||||||
'''
|
'''
|
||||||
dst = open(dst_fn, 'w') if dst_fn else None
|
dst = open(dst_fn, 'w') if dst_fn else None
|
||||||
printed = set()
|
printed = set()
|
||||||
|
@ -777,6 +782,7 @@ def write_dot(g, dot):
|
||||||
'''
|
'''
|
||||||
Arg: <graph> <file> - writes a graph into a file with custom attributes
|
Arg: <graph> <file> - writes a graph into a file with custom attributes
|
||||||
'''
|
'''
|
||||||
|
# Other similar external functions to_agraph agwrite
|
||||||
dot = str(dot)
|
dot = str(dot)
|
||||||
dot = open(dot, 'w')
|
dot = open(dot, 'w')
|
||||||
dot.write('strict digraph "None" {\n')
|
dot.write('strict digraph "None" {\n')
|
||||||
|
@ -867,6 +873,7 @@ def to_dg(a):
|
||||||
|
|
||||||
|
|
||||||
def remove_loops(dg):
|
def remove_loops(dg):
|
||||||
|
# srcxray.py "write_dot(remove_loops(read_dot('reduced.dot')), 'no-loops.dot')"
|
||||||
rm = []
|
rm = []
|
||||||
visited = set()
|
visited = set()
|
||||||
path = [object()]
|
path = [object()]
|
||||||
|
@ -903,6 +910,7 @@ def remove_couples(dg):
|
||||||
|
|
||||||
|
|
||||||
def rank_couples(dg):
|
def rank_couples(dg):
|
||||||
|
# a=sys_clone;srcxray.py "write_dot(rank_couples(reduce_graph(remove_loops(read_dot('$a.dot')))),'$a.dot')"
|
||||||
couples = []
|
couples = []
|
||||||
ranked = set()
|
ranked = set()
|
||||||
for n in dg:
|
for n in dg:
|
||||||
|
@ -1048,6 +1056,7 @@ def dot_expand(a, b):
|
||||||
|
|
||||||
|
|
||||||
def add_rank(g):
|
def add_rank(g):
|
||||||
|
# srcxray.py "write_dot(add_rank('reduced.dot'), 'ranked.dot')"
|
||||||
g = to_dg(g)
|
g = to_dg(g)
|
||||||
passed1 = set()
|
passed1 = set()
|
||||||
passed2 = set()
|
passed2 = set()
|
||||||
|
@ -1079,6 +1088,7 @@ def add_rank(g):
|
||||||
|
|
||||||
|
|
||||||
def import_symbols():
|
def import_symbols():
|
||||||
|
# extracts and import symbols from shared libraries
|
||||||
sym = my_graph('symbols')
|
sym = my_graph('symbols')
|
||||||
for l in popen('(shopt -s globstar; nm -D -C -A **/*.so.*)'):
|
for l in popen('(shopt -s globstar; nm -D -C -A **/*.so.*)'):
|
||||||
q = l.split(maxsplit=2)
|
q = l.split(maxsplit=2)
|
||||||
|
@ -1165,6 +1175,7 @@ def doxygen(*input):
|
||||||
def doxygen_xml(a):
|
def doxygen_xml(a):
|
||||||
'''
|
'''
|
||||||
Arg: <xml directory generated by doxygen> - extracts call graph
|
Arg: <xml directory generated by doxygen> - extracts call graph
|
||||||
|
Ex2: \"write_dot(doxygen_xml('xml'), 'doxygen.dot')\"
|
||||||
'''
|
'''
|
||||||
g = my_graph()
|
g = my_graph()
|
||||||
for x in list(glob.glob(os.path.join(a, "*.xml")) + [a]):
|
for x in list(glob.glob(os.path.join(a, "*.xml")) + [a]):
|
||||||
|
@ -1234,6 +1245,7 @@ def usage():
|
||||||
|
|
||||||
class _unittest_autotest(unittest.TestCase):
|
class _unittest_autotest(unittest.TestCase):
|
||||||
def test_1(self):
|
def test_1(self):
|
||||||
|
extract_referrer_test()
|
||||||
write_dot(nx.DiGraph([(1, 2), (2, 3), (2, 4)]), 'test.dot')
|
write_dot(nx.DiGraph([(1, 2), (2, 3), (2, 4)]), 'test.dot')
|
||||||
g = read_dot("test.dot")
|
g = read_dot("test.dot")
|
||||||
self.assertEqual(list(g.successors("2")), ["3", "4"])
|
self.assertEqual(list(g.successors("2")), ["3", "4"])
|
||||||
|
|
Loading…
Reference in New Issue