13b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch#!/usr/bin/env python 23b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Copyright 2016 the V8 project authors. All rights reserved. 33b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Use of this source code is governed by a BSD-style license that can be 43b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# found in the LICENSE file. 53b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 63b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch"""Script to transform and merge sancov files into human readable json-format. 73b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 83b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochThe script supports three actions: 93b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochall: Writes a json file with all instrumented lines of all executables. 103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochmerge: Merges sancov files with coverage output into an existing json file. 113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochsplit: Split json file into separate files per covered source file. 123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochThe json data is structured as follows: 143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch{ 153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch "version": 1, 163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch "tests": ["executable1", "executable2", ...], 173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch "files": { 183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch "file1": [[<instr line 1>, <bit_mask>], [<instr line 2>, <bit_mask>], ...], 193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch "file2": [...], 203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch ... 213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch} 233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochThe executables are sorted and determine the test bit mask. Their index+1 is 253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochthe bit, e.g. executable1 = 1, executable3 = 4, etc. Hence, a line covered by 263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochexecutable1 and executable3 will have bit_mask == 5 == 0b101. The number of 273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochtests is restricted to 52 in version 1, to allow javascript JSON parsing of 283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochthe bitsets encoded as numbers. JS max safe int is (1 << 53) - 1. 293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochThe line-number-bit_mask pairs are sorted by line number and don't contain 313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochduplicates. 323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochSplit json data preserves the same format, but only contains one file per 343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochjson file. 353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochThe sancov tool is expected to be in the llvm compiler-rt third-party 373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdirectory. It's not checked out by default and must be added as a custom deps: 383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch'v8/third_party/llvm/projects/compiler-rt': 393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'https://chromium.googlesource.com/external/llvm.org/compiler-rt.git' 403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch""" 413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport argparse 433b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport json 443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport logging 453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport os 463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport re 473b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport subprocess 483b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochimport sys 493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochfrom multiprocessing import Pool, cpu_count 513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochlogging.basicConfig(level=logging.INFO) 543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Files to exclude from coverage. Dropping their data early adds more speed. 563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# The contained cc files are already excluded from instrumentation, but inlined 573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# data is referenced through v8's object files. 583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochEXCLUSIONS = [ 593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'buildtools', 603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'src/third_party', 613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'third_party', 623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'test', 633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'testing', 643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch] 653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 663b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Executables found in the build output for which no coverage is generated. 673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Exclude them from the coverage data file. 683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochEXE_BLACKLIST = [ 693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'generate-bytecode-expectations', 703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'hello-world', 713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'mksnapshot', 723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'parser-shell', 733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'process', 743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'shell', 753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch] 763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# V8 checkout directory. 783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochBASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname( 793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.path.abspath(__file__)))) 803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Executable location. TODO(machenbach): Only release is supported for now. 823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochBUILD_DIR = os.path.join(BASE_DIR, 'out', 'Release') 833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Path prefix added by the llvm symbolizer including trailing slash. 853b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochOUTPUT_PATH_PREFIX = os.path.join(BUILD_DIR, '..', '..', '') 863b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 873b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# The sancov tool location. 883b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochSANCOV_TOOL = os.path.join( 893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch BASE_DIR, 'third_party', 'llvm', 'projects', 'compiler-rt', 903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'lib', 'sanitizer_common', 'scripts', 'sancov.py') 913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Simple script to sanitize the PCs from objdump. 933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochSANITIZE_PCS = os.path.join(BASE_DIR, 'tools', 'sanitizers', 'sanitize_pcs.py') 943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 953b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# The llvm symbolizer location. 963b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochSYMBOLIZER = os.path.join( 973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch BASE_DIR, 'third_party', 'llvm-build', 'Release+Asserts', 'bin', 983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'llvm-symbolizer') 993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Number of cpus. 1013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochCPUS = cpu_count() 1023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# Regexp to find sancov files as output by sancov_merger.py. Also grabs the 1043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch# executable name in group 1. 1053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben MurdochSANCOV_FILE_RE = re.compile(r'^(.*)\.result.sancov$') 1063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef executables(): 1093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Iterates over executable files in the build directory.""" 1103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for f in os.listdir(BUILD_DIR): 1113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_path = os.path.join(BUILD_DIR, f) 1123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (os.path.isfile(file_path) and 1133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.access(file_path, os.X_OK) and 1143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch f not in EXE_BLACKLIST): 1153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch yield file_path 1163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef process_symbolizer_output(output): 1193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Post-process llvm symbolizer output. 1203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Excludes files outside the v8 checkout or given in exclusion list above 1223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch from further processing. Drops the character index in each line. 1233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Returns: A mapping of file names to lists of line numbers. The file names 1253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch have relative paths to the v8 base directory. The lists of line 1263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch numbers don't contain duplicate lines and are sorted. 1273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 1283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Drop path prefix when iterating lines. The path is redundant and takes 1293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # too much space. Drop files outside that path, e.g. generated files in 1303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # the build dir and absolute paths to c++ library headers. 1313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def iter_lines(): 1323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for line in output.strip().splitlines(): 1333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if line.startswith(OUTPUT_PATH_PREFIX): 1343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch yield line[len(OUTPUT_PATH_PREFIX):] 1353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Map file names to sets of instrumented line numbers. 1373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_map = {} 1383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for line in iter_lines(): 1393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Drop character number, we only care for line numbers. Each line has the 1403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # form: <file name>:<line number>:<character number>. 1413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_name, number, _ = line.split(':') 1423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_map.setdefault(file_name, set([])).add(int(number)) 1433b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Remove exclusion patterns from file map. It's cheaper to do it after the 1453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # mapping, as there are few excluded files and we don't want to do this 1463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # check for numerous lines in ordinary files. 1473b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def keep(file_name): 1483b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for e in EXCLUSIONS: 1493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if file_name.startswith(e): 1503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return False 1513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return True 1523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Return in serializable form and filter. 1543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return {k: sorted(file_map[k]) for k in file_map if keep(k)} 1553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef get_instrumented_lines(executable): 1583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Return the instrumented lines of an executable. 1593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Called trough multiprocessing pool. 1613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Returns: Post-processed llvm output as returned by process_symbolizer_output. 1633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 1643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # The first two pipes are from llvm's tool sancov.py with 0x added to the hex 1653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # numbers. The results are piped into the llvm symbolizer, which outputs for 1663b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # each PC: <file name with abs path>:<line number>:<character number>. 1673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # We don't call the sancov tool to get more speed. 1683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch process = subprocess.Popen( 1693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'objdump -d %s | ' 1703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'grep \'^\s\+[0-9a-f]\+:.*\scall\(q\|\)\s\+[0-9a-f]\+ ' 1713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch '<__sanitizer_cov\(_with_check\|\)\(@plt\|\)>\' | ' 1723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'grep \'^\s\+[0-9a-f]\+\' -o | ' 1733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch '%s | ' 1743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch '%s --obj %s -functions=none' % 1753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch (executable, SANITIZE_PCS, SYMBOLIZER, executable), 1763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stdout=subprocess.PIPE, 1773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stderr=subprocess.PIPE, 1783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stdin=subprocess.PIPE, 1793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch cwd=BASE_DIR, 1803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch shell=True, 1813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch ) 1823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch output, _ = process.communicate() 1833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert process.returncode == 0 1843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return process_symbolizer_output(output) 1853b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1863b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1873b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef merge_instrumented_line_results(exe_list, results): 1883b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Merge multiprocessing results for all instrumented lines. 1893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Args: 1913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch exe_list: List of all executable names with absolute paths. 1923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch results: List of results as returned by get_instrumented_lines. 1933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Returns: Dict to be used as json data as specified on the top of this page. 1953b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch The dictionary contains all instrumented lines of all files 1963b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch referenced by all executables. 1973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 1983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def merge_files(x, y): 1993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for file_name, lines in y.iteritems(): 2003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch x.setdefault(file_name, set([])).update(lines) 2013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return x 2023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch result = reduce(merge_files, results, {}) 2033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Return data as file->lines mapping. The lines are saved as lists 2053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # with (line number, test bits (as int)). The test bits are initialized with 2063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # 0, meaning instrumented, but no coverage. 2073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # The order of the test bits is given with key 'tests'. For now, these are 2083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # the executable names. We use a _list_ with two items instead of a tuple to 2093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # ease merging by allowing mutation of the second item. 2103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return { 2113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'version': 1, 2123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'tests': sorted(map(os.path.basename, exe_list)), 2133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 'files': {f: map(lambda l: [l, 0], sorted(result[f])) for f in result}, 2143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef write_instrumented(options): 2183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Implements the 'all' action of this tool.""" 2193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch exe_list = list(executables()) 2203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Reading instrumented lines from %d executables.', 2213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch len(exe_list)) 2223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch pool = Pool(CPUS) 2233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch try: 2243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch results = pool.imap_unordered(get_instrumented_lines, exe_list) 2253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch finally: 2263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch pool.close() 2273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Merge multiprocessing results and prepare output data. 2293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data = merge_instrumented_line_results(exe_list, results) 2303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Read data from %d executables, which covers %d files.', 2323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch len(data['tests']), len(data['files'])) 2333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Writing results to %s', options.json_output) 2343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Write json output. 2363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch with open(options.json_output, 'w') as f: 2373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch json.dump(data, f, sort_keys=True) 2383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef get_covered_lines(args): 2413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Return the covered lines of an executable. 2423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2433b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Called trough multiprocessing pool. The args are expected to unpack to: 2443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch cov_dir: Folder with sancov files merged by sancov_merger.py. 2453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch executable: The executable that was called to produce the given coverage 2463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data. 2473b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch sancov_file: The merged sancov file with coverage data. 2483b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Returns: A tuple of post-processed llvm output as returned by 2503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch process_symbolizer_output and the executable name. 2513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 2523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch cov_dir, executable, sancov_file = args 2533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Let the sancov tool print the covered PCs and pipe them through the llvm 2553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # symbolizer. 2563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch process = subprocess.Popen( 2573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch '%s print %s 2> /dev/null | ' 2583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch '%s --obj %s -functions=none' % 2593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch (SANCOV_TOOL, 2603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.path.join(cov_dir, sancov_file), 2613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch SYMBOLIZER, 2623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.path.join(BUILD_DIR, executable)), 2633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stdout=subprocess.PIPE, 2643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stderr=subprocess.PIPE, 2653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch stdin=subprocess.PIPE, 2663b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch cwd=BASE_DIR, 2673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch shell=True, 2683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch ) 2693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch output, _ = process.communicate() 2703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert process.returncode == 0 2713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return process_symbolizer_output(output), executable 2723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef merge_covered_line_results(data, results): 2753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Merge multiprocessing results for covered lines. 2763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch The data is mutated, the results are merged into it in place. 2783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Args: 2803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data: Existing coverage data from json file containing all instrumented 2813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch lines. 2823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch results: List of results as returned by get_covered_lines. 2833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 2843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2853b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # List of executables and mapping to the test bit mask. The number of 2863b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # tests is restricted to 52, to allow javascript JSON parsing of 2873b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # the bitsets encoded as numbers. JS max safe int is (1 << 53) - 1. 2883b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch exe_list = data['tests'] 2893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert len(exe_list) <= 52, 'Max 52 different tests are supported.' 2903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch test_bit_masks = {exe:1<<i for i, exe in enumerate(exe_list)} 2913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def merge_lines(old_lines, new_lines, mask): 2933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Merge the coverage data of a list of lines. 2943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2953b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Args: 2963b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch old_lines: Lines as list of pairs with line number and test bit mask. 2973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch The new lines will be merged into the list in place. 2983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch new_lines: List of new (covered) lines (sorted). 2993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch mask: The bit to be set for covered lines. The bit index is the test 3003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch index of the executable that covered the line. 3013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 3023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch i = 0 3033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Iterate over old and new lines, both are sorted. 3043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for l in new_lines: 3053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch while old_lines[i][0] < l: 3063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Forward instrumented lines not present in this coverage data. 3073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch i += 1 3083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # TODO: Add more context to the assert message. 3093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert i < len(old_lines), 'Covered line %d not in input file.' % l 3103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert old_lines[i][0] == l, 'Covered line %d not in input file.' % l 3113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Add coverage information to the line. 3133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch old_lines[i][1] |= mask 3143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def merge_files(data, result): 3163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Merge result into data. 3173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch The data is mutated in place. 3193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Args: 3213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data: Merged coverage data from the previous reduce step. 3223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch result: New result to be merged in. The type is as returned by 3233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch get_covered_lines. 3243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """ 3253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_map, executable = result 3263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch files = data['files'] 3273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for file_name, lines in file_map.iteritems(): 3283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch merge_lines(files[file_name], lines, test_bit_masks[executable]) 3293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return data 3303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch reduce(merge_files, results, data) 3323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef merge(options): 3353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Implements the 'merge' action of this tool.""" 3363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Check if folder with coverage output exists. 3383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch assert (os.path.exists(options.coverage_dir) and 3393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.path.isdir(options.coverage_dir)) 3403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Inputs for multiprocessing. List of tuples of: 3423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Coverage dir, executable name, sancov file name. 3433b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch inputs = [] 3443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for f in os.listdir(options.coverage_dir): 3453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch match = SANCOV_FILE_RE.match(f) 3463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if match: 3473b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch inputs.append((options.coverage_dir, match.group(1), f)) 3483b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Merging %d sancov files into %s', 3503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch len(inputs), options.json_input) 3513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Post-process covered lines in parallel. 3533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch pool = Pool(CPUS) 3543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch try: 3553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch results = pool.imap_unordered(get_covered_lines, inputs) 3563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch finally: 3573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch pool.close() 3583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Load existing json data file for merging the results. 3603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch with open(options.json_input, 'r') as f: 3613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data = json.load(f) 3623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Merge muliprocessing results. Mutates data. 3643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch merge_covered_line_results(data, results) 3653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3663b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Merged data from %d executables, which covers %d files.', 3673b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch len(data['tests']), len(data['files'])) 3683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Writing results to %s', options.json_output) 3693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Write merged results to file. 3713b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch with open(options.json_output, 'w') as f: 3723b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch json.dump(data, f, sort_keys=True) 3733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3743b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3753b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef split(options): 3763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch """Implements the 'split' action of this tool.""" 3773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Load existing json data file for splitting. 3783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch with open(options.json_input, 'r') as f: 3793b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch data = json.load(f) 3803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3813b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch logging.info('Splitting off %d coverage files from %s', 3823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch len(data['files']), options.json_input) 3833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for file_name, coverage in data['files'].iteritems(): 3853b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Preserve relative directories that are part of the file name. 3863b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch file_path = os.path.join(options.output_dir, file_name + '.json') 3873b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch try: 3883b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch os.makedirs(os.path.dirname(file_path)) 3893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch except OSError: 3903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Ignore existing directories. 3913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch pass 3923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch with open(file_path, 'w') as f: 3943b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Flat-copy the old dict. 3953b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch new_data = dict(data) 3963b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 3973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Update current file. 3983b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch new_data['files'] = {file_name: coverage} 3993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # Write json data. 4013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch json.dump(new_data, f, sort_keys=True) 4023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochdef main(args=None): 4053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser = argparse.ArgumentParser() 4063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser.add_argument('--coverage-dir', 4073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch help='Path to the sancov output files.') 4083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser.add_argument('--json-input', 4093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch help='Path to an existing json file with coverage data.') 4103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser.add_argument('--json-output', 4113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch help='Path to a file to write json output to.') 4123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser.add_argument('--output-dir', 4133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch help='Directory where to put split output files to.') 4143b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch parser.add_argument('action', choices=['all', 'merge', 'split'], 4153b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch help='Action to perform.') 4163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch options = parser.parse_args(args) 4183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if options.action.lower() == 'all': 4193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.json_output: 4203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--json-output is required' 4213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch write_instrumented(options) 4233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch elif options.action.lower() == 'merge': 4243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.coverage_dir: 4253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--coverage-dir is required' 4263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.json_input: 4283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--json-input is required' 4293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.json_output: 4313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--json-output is required' 4323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4333b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch merge(options) 4343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch elif options.action.lower() == 'split': 4353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.json_input: 4363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--json-input is required' 4373b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if not options.output_dir: 4393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print '--output-dir is required' 4403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 1 4413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch split(options) 4423b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return 0 4433b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 4453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochif __name__ == '__main__': 4463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch sys.exit(main()) 447