Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 57 additions & 55 deletions Utilities/StaticAnalyzers/scripts/callgraph.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,83 @@
#! /usr/bin/env python3
from __future__ import print_function
import networkx as nx
import re
import yaml

topfunc = re.compile(r"::(accumulate|acquire|startingNewLoop|duringLoop|endOfLoop|beginOfJob|endOfJob|produce|analyze|filter|beginLuminosityBlock|beginRun|beginStream|streamBeginRun|streamBeginLuminosityBlock|streamEndRun|streamEndLuminosityBlock|globalBeginRun|globalEndRun|globalBeginLuminosityBlock|globalEndLuminosityBlock|endRun|endLuminosityBlock)\(")

baseclass = re.compile(r"edm::(one::|stream::|global::)?(ED(Producer|Filter|Analyzer|(IterateNTimes|NavigateEvents)?Looper)(Base)?|impl::(ExternalWork|Accumulator))")
baseclass = re.compile(
r"edm::(one::|stream::|global::)?(ED(Producer|Filter|Analyzer|(IterateNTimes|NavigateEvents)?Looper)(Base)?|impl::(ExternalWork|Accumulator))")
farg = re.compile(r"\(.*?\)")
tmpl = re.compile(r'<.*?>')
toplevelfuncs = set()
epfuncre = re.compile(r"edm::eventsetup::EventSetupRecord::get<.*>\(.*\)")
skipfunc = re.compile(r"TGraph::IsA\(.*\)")
epfuncs=set()
epfuncs = set()

import networkx as nx
G=nx.DiGraph()
G = nx.DiGraph()

#g = open('module_to_package.txt')
#module2package=dict()
#for line in g:
# fields = line.strip().split(';')
# if len(fields) <2:
# continue
# module2package.setdefault(fields[1], []).append(fields[0])
# g = open('module_to_package.txt')
# module2package=dict()
# for line in g:
# fields = line.strip().split(';')
# if len(fields) <2:
# continue
# module2package.setdefault(fields[1], []).append(fields[0])
#
#i = open('module_to_package.yaml', 'w')
#yaml.dump(module2package, i)
#i.close()
# i = open('module_to_package.yaml', 'w')
# yaml.dump(module2package, i)
# i.close()

h = open('module_to_package.yaml', 'r')
module2package=yaml.load(h, Loader=yaml.FullLoader)
module2package = yaml.load(h, Loader=yaml.FullLoader)

with open('function-calls-db.txt') as f:
for line in f :
fields = line.split("'")
for line in f:
fields = line.split("'")
if len(fields) < 3:
continue
if fields[2] == ' calls function ' :
if not skipfunc.search(line) :
G.add_edge(fields[1],fields[3],kind=fields[2])
if epfuncre.search(fields[3]) :
epfuncs.add(fields[3])
if fields[2] == ' overrides function ' :
if baseclass.search(fields[3]) :
if topfunc.search(fields[3]) :
toplevelfuncs.add(fields[1])
G.add_edge(fields[1],fields[3],kind=' overrides function ')
else :
if not skipfunc.search(line) :
G.add_edge(fields[3],fields[1],kind=' calls override function ')
if epfuncre.search(fields[1]) : epfuncs.add(fields[1])


if fields[2] == ' calls function ':
if not skipfunc.search(line):
G.add_edge(fields[1], fields[3], kind=fields[2])
if epfuncre.search(fields[3]):
epfuncs.add(fields[3])
if fields[2] == ' overrides function ':
if baseclass.search(fields[3]):
if topfunc.search(fields[3]):
toplevelfuncs.add(fields[1])
G.add_edge(fields[1], fields[3], kind=' overrides function ')
else:
if not skipfunc.search(line):
G.add_edge(fields[3], fields[1],
kind=' calls override function ')
if epfuncre.search(fields[1]):
epfuncs.add(fields[1])

callstacks=set()
callstacks = set()
for tfunc in toplevelfuncs:
for epfunc in epfuncs:
if G.has_node(tfunc) and G.has_node(epfunc) and nx.has_path(G,tfunc,epfunc) :
path = nx.shortest_path(G,tfunc,epfunc)
cs=str("")
previous=str("")
for p in path :
if epfuncre.search(p): break
stripped=re.sub(farg,"()",p)
if previous != stripped:
cs+=' '+stripped+";"
previous = stripped
callstacks.add(cs)
break
for epfunc in epfuncs:
if G.has_node(tfunc) and G.has_node(epfunc) and nx.has_path(G, tfunc, epfunc):
path = nx.shortest_path(G, tfunc, epfunc)
cs = str("")
previous = str("")
for p in path:
if epfuncre.search(p):
break
stripped = re.sub(farg, "()", p)
if previous != stripped:
cs += ' ' + stripped + ";"
previous = stripped
callstacks.add(cs)
break


report=dict()
report = dict()
for key in sorted(module2package.keys()):
for value in sorted(module2package[key]):
vre=re.compile(' %s::.*();' % value)
for cs in sorted(callstacks):
if vre.search(cs):
report.setdefault(key, {}).setdefault(value, []).append(cs)
r=open('eventsetuprecord-get.yaml', 'w')
yaml.dump(report,r)
for value in sorted(module2package[key]):
vre = re.compile(' %s::.*();' % value)
for cs in sorted(callstacks):
if vre.search(cs):
report.setdefault(key, {}).setdefault(value, []).append(cs)
r = open('eventsetuprecord-get.yaml', 'w')
yaml.dump(report, r)
154 changes: 82 additions & 72 deletions Utilities/StaticAnalyzers/scripts/class-composition.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
#! /usr/bin/env python3
from __future__ import print_function
import networkx as nx
import re
stdcl = re.compile("^std::(.*)[^>]$")
stdptr = re.compile("(.*)_ptr$")
datacl = re.compile("^class ")
bfunc = re.compile("^function ")
mbcl = re.compile("(base|data) class")
farg = re.compile("(.*)\(\w+\)")
nsep = re.compile("\:\:")
topfunc = re.compile("::(produce|analyze|filter|beginLuminosityBlock|beginRun|beginStream)\(")
baseclass = re.compile("edm::(one::|stream::|global::)?ED(Producer|Filter|Analyzer)(Base)?")
getfunc = re.compile("edm::eventsetup::EventSetupRecord::get\<.*\>\((.*)&\) const")
farg = re.compile(r"(.*)\(\w+\)")
nsep = re.compile(r"\:\:")
topfunc = re.compile(
r"::(produce|analyze|filter|beginLuminosityBlock|beginRun|beginStream)\(")
baseclass = re.compile(
"edm::(one::|stream::|global::)?ED(Producer|Filter|Analyzer)(Base)?")
getfunc = re.compile(
r"edm::eventsetup::EventSetupRecord::get\<.*\>\((.*)&\) const")
handle = re.compile("(.*),?class edm::ES(.*)Handle<(.*)>")
statics = set()
toplevelfuncs = set()
Expand All @@ -26,82 +30,88 @@
memberclasses = set()
derivedclasses = set()

import networkx as nx
G=nx.DiGraph()
H=nx.DiGraph()
I=nx.DiGraph()
Gdg = nx.DiGraph()
Hdg = nx.DiGraph()
Idg = nx.DiGraph()


f = open('classes.txt.dumperall')
for line in f :
if mbcl.search(line) :
fields = line.split("'")
if fields[2] == ' member data class ':
if not stdcl.search(fields[2]) : H.add_edge(fields[1],fields[3],kind=fields[2])
if fields[2] == ' templated member data class ':
H.add_edge(fields[1],fields[5],kind=fields[3])
if fields[2] == ' base class ':
H.add_edge(fields[1],fields[3],kind=fields[2])
I.add_edge(fields[3],fields[1],kind=' derived class')
for line in f:
if mbcl.search(line):
fields = line.split("'")
if fields[2] == ' member data class ':
if not stdcl.search(fields[2]):
Hdg.add_edge(fields[1], fields[3], kind=fields[2])
if fields[2] == ' templated member data class ':
Hdg.add_edge(fields[1], fields[5], kind=fields[3])
if fields[2] == ' base class ':
Hdg.add_edge(fields[1], fields[3], kind=fields[2])
Idg.add_edge(fields[3], fields[1], kind=' derived class')
f.close()

f = open('function-calls-db.txt')

for line in f :
if not bfunc.search(line) : continue
fields = line.split("'")
if fields[2] == ' calls function ' :
G.add_edge(fields[1],fields[3],kind=' calls function ')
if getfunc.search(fields[3]) :
dataclassfuncs.add(fields[3])
m = getfunc.match(fields[3])
n = handle.match(m.group(1))
if n : o = n.group(3)
else : o = m.group(1)
p = re.sub("class ","",o)
dataclass = re.sub("struct ","",p)
dataclasses.add(dataclass)
if fields[2] == ' overrides function ' :
if baseclass.search(fields[3]) :
G.add_edge(fields[1],fields[3],kind=' overrides function ')
if topfunc.search(fields[3]) : toplevelfuncs.add(fields[1])
else : G.add_edge(fields[3],fields[1], kind=' calls override function ')
if fields[2] == ' static variable ' :
G.add_edge(fields[1],fields[3],kind=' static variable ')
statics.add(fields[3])
for line in f:
if not bfunc.search(line):
continue
fields = line.split("'")
if fields[2] == ' calls function ':
Gdg.add_edge(fields[1], fields[3], kind=' calls function ')
if getfunc.search(fields[3]):
dataclassfuncs.add(fields[3])
m = getfunc.match(fields[3])
n = handle.match(m.group(1))
if n:
o = n.group(3)
else:
o = m.group(1)
p = re.sub("class ", "", o)
dataclass = re.sub("struct ", "", p)
dataclasses.add(dataclass)
if fields[2] == ' overrides function ':
if baseclass.search(fields[3]):
Gdg.add_edge(fields[1], fields[3], kind=' overrides function ')
if topfunc.search(fields[3]):
toplevelfuncs.add(fields[1])
else:
Gdg.add_edge(fields[3], fields[1], kind=' calls override function ')
if fields[2] == ' static variable ':
Gdg.add_edge(fields[1], fields[3], kind=' static variable ')
statics.add(fields[3])
f.close()

visited = set()
nodes = sorted(dataclasses)
for node in nodes:
if node in visited:
continue
visited.add(node)
if node in H : stack = [(node,iter(H[node]))]
if node in I :
Q=nx.dfs_preorder_nodes(I,node)
for q in Q:
print("class '"+q+"'")
if q in H :
stack.append( ( q, iter( H[q] ) ) )
while stack:
parent,children = stack[-1]
print("class '"+parent+"'")
try:
child = next(children)
if child not in visited:
visited.add(child)
if not stdcl.search(child):
print("class '"+child+"'")
stack.append( ( child, iter( H[child] ) ) )
kind=H[parent][child]['kind']
print(parent, kind, child)
if stdptr.search(kind):
if child in I :
Q=nx.dfs_preorder_nodes(I,child)
for q in Q :
print("class '"+q+"'")
if q in H :
stack.append( ( q, iter( H[q] ) ) )
except StopIteration:
stack.pop()
if node in visited:
continue
visited.add(node)
if node in Hdg:
stack = [(node, iter(Hdg[node]))]
if node in Idg:
Qdg = nx.dfs_preorder_nodes(Idg, node)
for q in Qdg:
print("class '"+q+"'")
if q in Hdg:
stack.append((q, iter(Hdg[q])))
while stack:
parent, children = stack[-1]
print("class '"+parent+"'")
try:
child = next(children)
if child not in visited:
visited.add(child)
if not stdcl.search(child):
print("class '"+child+"'")
stack.append((child, iter(Hdg[child])))
kind = Hdg[parent][child]['kind']
print(parent, kind, child)
if stdptr.search(kind):
if child in Idg:
Qdg = nx.dfs_preorder_nodes(Idg, child)
for q in Qdg:
print("class '"+q+"'")
if q in Hdg:
stack.append((q, iter(Hdg[q])))
except StopIteration:
stack.pop()
12 changes: 6 additions & 6 deletions Utilities/StaticAnalyzers/scripts/classnames-extract.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#! /usr/bin/env python3

f = open('classes.txt','r')
g = open('classnames.txt','w')
for line in f :
fields = line.split("'")
if fields[0] == 'class ' :
g.write(fields[1]+'\n')
f = open('classes.txt', 'r')
g = open('classnames.txt', 'w')
for line in f:
fields = line.split("'")
if fields[0] == 'class ':
g.write(fields[1]+'\n')

f.close()
g.close()
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ sort -u edm-global-classes.txt.unsorted | grep -v -e"^EDM global class " >edm-gl
if [ ! -f ./callgraph.py ]
then
cp -pv ${CMSSW_BASE}/src/Utilities/StaticAnalyzers/scripts/callgraph.py .
cp -pv ${CMSSW_BASE}/src/Utilities/StaticAnalyzers/scripts/modules_to_package.yaml .
cp -pv ${CMSSW_BASE}/src/Utilities/StaticAnalyzers/scripts/module_to_package.yaml .
fi
touch eventsetuprecord-get-all.txt eventsetuprecord-get.txt
./callgraph.py 2>&1 | tee eventsetuprecord-get.txt
Loading