diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKitTools/CodeCoverage/run-generate-coverage-data --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKitTools/CodeCoverage/run-generate-coverage-data Mon Mar 30 12:54:55 2009 +0300 @@ -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"