summaryrefslogtreecommitdiffstats
path: root/WebKitTools/CodeCoverage/run-generate-coverage-data
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/CodeCoverage/run-generate-coverage-data')
-rwxr-xr-xWebKitTools/CodeCoverage/run-generate-coverage-data240
1 files changed, 240 insertions, 0 deletions
diff --git a/WebKitTools/CodeCoverage/run-generate-coverage-data b/WebKitTools/CodeCoverage/run-generate-coverage-data
new file mode 100755
index 0000000..a87da1d
--- /dev/null
+++ b/WebKitTools/CodeCoverage/run-generate-coverage-data
@@ -0,0 +1,240 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2004, 2005, 2006 Nathaniel Smith
+# Copyright (C) 2007 Holger Hans Peter Freyther
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os, sys
+
+# from BitBake
+def mkdirhier(dir):
+ """Create a directory like 'mkdir -p', but does not complain if
+ directory already exists like os.makedirs
+ """
+ try:
+ os.makedirs(dir)
+ except OSError, e:
+ if e.errno != 17: raise e
+
+def collect_base(src,match_array):
+ """
+ Collect all files that match the match_array.
+ """
+
+ sources = []
+ for root, dirs, files in os.walk(src):
+ if ".svn" in root:
+ continue
+
+ for file in files:
+ base,ext = os.path.splitext(file)
+ if ext in match_array:
+ sources.append( os.path.join(root, file) )
+
+ return sources
+
+def collect_depends(src):
+ return collect_base(src, [".d"])
+
+def parse_dependency_file(src, base_dir, black_list):
+ """
+ Parse the .d files of the gcc
+
+ Wow, the first time os.path.join is doing the right thing. We might
+ have a relative path in the depends using os.path.join(dirname of .d, dep)
+ we will end up in
+ """
+ file = open(src)
+ file = file.read()
+ file = file.replace('\\', '').replace('\n', '')
+
+ # We now have object: dependencies splitted
+ ar = file.split(':', 1)
+ obj = ar[0].strip()
+ dir = os.path.dirname(obj)
+ deps = ar[1].split(' ')
+
+ # Remove files outside WebKit, make path absolute
+ deps = filter(lambda x: base_dir in x, deps)
+ deps = map(lambda x: os.path.abspath(os.path.join(dir, x)), deps)
+ return (obj, dir, deps)
+
+def collect_cov(base_path,targets):
+ """
+ Collect gcov files, collect_sources is not used as it also creates
+ dirs and needs to do substituting.
+ Actually we will build a mapping from source file to gcov files of
+ interest. This is because we could have bytestream.h in many different
+ subdirectories. And we would endup with bla.cpp##bytestream.h and we
+ do not know which bytestream file was tested
+ """
+ def find_source_file(root,cov_file):
+ """ Find a Source line or crash
+
+ '#Users#ich#projekte#src#threadmessage.cpp###space#dports#include#qt3#qstring.h.gcov'
+ '#Users#ich#projekte#src#threadmessage.cpp##..#^#src#threadmessage.cpp.gcov'
+
+ ### is absolute path
+ ##..#^# is relative path... well a gcov bug as well
+ ## normal split file in the same directory
+ """
+ if '###' in cov_file:
+ split = cov_file.split('###')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.join(os.path.sep,filepath)
+ elif '##..#^#' in cov_file:
+ split = cov_file.split('##..#^#')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.abspath(os.path.join(root,os.path.pardir,os.path.pardir,filepath))
+ elif '##' in cov_file:
+ split = cov_file.split('##')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.abspath(os.path.join(root,filepath))
+ elif '#' in cov_file:
+ # wow a not broken gcov on OSX
+ basename=os.path.basename(cov_file).replace('#',os.path.sep)[:-5]
+ return os.path.abspath(os.path.join(root,basename))
+
+ else:
+ raise "No source found %s" % cov_file
+
+ def sanitize_path(path):
+ """
+ Well fix up paths once again /usr/lib/gcc/i486-linux-gnu/4.1.2/^/^/^/^/include/c++/4.1.2/bits/stl_pair.h
+ according to gcov '^' is a relative path, we will now build one from this one. Somehow it depends
+ on the gcov version if .. really gets replaced to ^....
+ """
+ import os
+ split = path.split(os.path.sep)
+ str = ""
+ for part in split:
+ if part == '':
+ str = os.path.sep
+ elif part == '^':
+ str = "%s..%s" % (str,os.path.sep)
+ else:
+ str = "%s%s%s" % (str,part,os.path.sep)
+ return os.path.abspath(str)
+
+
+ gcov = {}
+ for root, dirs, files in os.walk(base_path):
+ if ".svn" in root:
+ continue
+ for file in files:
+ base,ext = os.path.splitext(file)
+ if ext in [".gcov"]:
+ try:
+ cov = os.path.join(root, file)
+ src = find_source_file( root, cov )
+ src = sanitize_path( src )
+
+ if not src in gcov:
+ gcov[src] = []
+ gcov[src].append( cov )
+ except Exception,e:
+ print "Exception on ", e
+ #import sys
+ #sys.exit(0)
+ pass
+
+ #print gcov
+ return gcov
+
+def generate_covs(candidates):
+ """
+ Generate gcov files in the right directory
+
+ candidtaes contains the directories we have used when
+ building. Each directory contains a set of files we will
+ try to generate gcov files for.
+ """
+ print candidates.keys()
+ for dir in candidates.keys():
+ print "Trying in %s" % (dir)
+ for dep in candidates[dir].keys():
+ cmd = "cd %s; gcov -p -l %s" % (dir, dep)
+ os.system("%s > /dev/null 2>&1 " % cmd)
+
+
+def analyze_coverage(sources,data,dirs,runid,base):
+ """
+ sources actual source files relative to src_dir e.g kdelibs/kdecore/klibloader.cpp
+ data Where to put the stuff
+ dirs Where to take a look for gcov files
+ base The base directory for files. All files not inside base will be ignored
+ """
+ import cov
+ print base
+ gcov = collect_cov(base,dirs)
+ result = cov.analyze_coverage(gcov, sources, runid, data, base)
+ print result
+
+if __name__ == "__main__":
+ #global targets
+ if not len(sys.argv) == 3:
+ print "This script needs three parameters"
+ print "Call it with generate_cov RUNID ResultsDir"
+ sys.exit(-1)
+ runid = sys.argv[1]
+ results = sys.argv[2]
+
+ # create directories for out result
+ mkdirhier(results)
+
+ print "Collection Sources and preparing data tree"
+ base_dir = os.path.abspath(os.path.curdir)
+ depends = collect_depends(base_dir)
+ candidates = map(lambda x: parse_dependency_file(x,base_dir,[]), depends)
+
+ # Build a number of sources from the candidates. This is a Set for the poor
+ # Two level dict. One for
+ dirs = {}
+ files = {}
+ for (_,dir,deps) in candidates:
+ if not dir in dirs:
+ dirs[dir] = {}
+ for dep in deps:
+ if not dep in dirs[dir]:
+ dirs[dir][dep] = dep
+ if not dep in files:
+ files[dep] = dep
+
+ sources = files.keys()
+
+ print "Found %d candidates" % (len(sources))
+ print "Will run inefficient generation of gcov files now"
+ generate_covs(dirs)
+
+ print "Analyzing Gcov"
+ analyze_coverage(sources, results, dirs.keys(), runid, base_dir)
+ print "Done"