Hi, I am sending patches for rtems-tools repo. These patches are results of my development during ESA SOCIS 2014. They introduces coverage analysis into rtems-test command in rtems-tools repo.
Blog post about how to setup the environment and get coverage analysis working in new way can be found here: http://kmiesowicz.blogspot.com/2014/08/new-approach-to-coverage-analysis-in.html There are still some issues - for example symbol set configuration file which now has to be manually adjusted to RTEMS build path. This is inconvenient and I will continue work to improve this. I'm looking forward to your reviews and comments. Regards Krzysztof Miesowicz
From 6b7b2937eb25b31d1c1162efd95b6a18365cb277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 13:16:17 +0200 Subject: [PATCH 01/12] --coverage feature added to rtems-test command + pc386 BSP support for rtems-test --- rtemstoolkit/options.py | 2 + tester/rt/coverage.py | 264 +++++++++++++++++++++++++++++++++++++ tester/rt/test.py | 20 ++- tester/rtems/testing/bsps/pc386.mc | 57 ++++++++ tester/rtems/testing/coverage.mc | 48 +++++++ tester/rtems/testing/gdb.cfg | 7 + tester/rtems/testing/qemu.cfg | 17 ++- 7 files changed, 412 insertions(+), 3 deletions(-) create mode 100644 tester/rt/coverage.py create mode 100644 tester/rtems/testing/bsps/pc386.mc create mode 100644 tester/rtems/testing/coverage.mc diff --git a/rtemstoolkit/options.py b/rtemstoolkit/options.py index 97b8ba7..5aa1ed3 100644 --- a/rtemstoolkit/options.py +++ b/rtemstoolkit/options.py @@ -91,6 +91,7 @@ class command_line(object): '--keep-going' : ('_keep_going', self._lo_bool, False, '0', True), '--always-clean' : ('_always_clean', self._lo_bool, False, '0', True), '--no-install' : ('_no_install', self._lo_bool, False, '0', True), + '--coverage' : ('_coverage', self._lo_bool, False, '0', False), '--help' : (None, self._lo_help, False, None, False) } self.long_opts_help = { @@ -105,6 +106,7 @@ class command_line(object): '--jobs=[0..n,none,half,full]': 'Run with specified number of jobs, default: num CPUs.', '--macros file[,file]': 'Macro format files to load after the defaults', '--log file': 'Log file where all build out is written too', + '--coverage': 'Perform coverage analysis' } self.opts = { 'params' : [] } self.command_path = command_path diff --git a/tester/rt/coverage.py b/tester/rt/coverage.py new file mode 100644 index 0000000..e170607 --- /dev/null +++ b/tester/rt/coverage.py @@ -0,0 +1,264 @@ +''' +Created on Jul 7, 2014 + +@author: Krzysztof Mięsowicz <krzysztof.miesow...@gmail.com> +''' +from rtemstoolkit import path +from rtemstoolkit import log +from rtemstoolkit import execute +from rtemstoolkit import macros +import os +from datetime import datetime + +class summary: + def __init__(self, p_summaryDir): + self.summaryFilePath = path.join(p_summaryDir, "summary.txt") + self.indexFilePath = path.join(p_summaryDir, "index.html") + self.bytes_analyzed = 0 + self.bytes_notExecuted = 0 + self.percentage_executed = 0.0 + self.percentage_notExecuted = 100.0 + self.ranges_uncovered = 0 + self.branches_uncovered = 0 + self.branches_total = 0 + self.branches_alwaysTaken = 0 + self.branches_neverTaken = 0 + self.percentage_branchesCovered = 0.0 + + def parse(self): + if(not path.exists(self.summaryFilePath)): + log.warning("Summary file " + self.summaryFilePath + " does not exist!") + return + + summaryFile = open(self.summaryFilePath,'r') + self.bytes_analyzed = self._getValueFromNextLineWithColon(summaryFile) + self.bytes_notExecuted = self._getValueFromNextLineWithColon(summaryFile) + self.percentage_executed = self._getValueFromNextLineWithColon(summaryFile) + self.percentage_notExecuted = self._getValueFromNextLineWithColon(summaryFile) + self.ranges_uncovered = self._getValueFromNextLineWithColon(summaryFile) + self.branches_total = self._getValueFromNextLineWithColon(summaryFile) + self.branches_uncovered = self._getValueFromNextLineWithColon(summaryFile) + self.branches_alwaysTaken = self._getValueFromNextLineWithoutColon(summaryFile) + self.branches_neverTaken = self._getValueFromNextLineWithoutColon(summaryFile) + summaryFile.close() + + self.percentage_branchesCovered = 1 - float(self.branches_uncovered) / float(self.branches_total) + return + + def _getValueFromNextLineWithColon(self, summaryFile): + line = summaryFile.readline() + return line.split(':')[1].strip() + + def _getValueFromNextLineWithoutColon(self, summaryFile): + line = summaryFile.readline() + return line.strip().split(' ')[0] + +class reportGen: + def __init__(self, p_symbolSetsList, p_targetDir): + self.symbolSetsList = p_symbolSetsList + self.targetDir = p_targetDir + self.partialReportsFiles = list(["index.html", "summary.txt"]) + + def _findPartialReports(self): + partialReports = {} + for symbolSet in self.symbolSetsList: + setSummary = summary(path.join(self.targetDir, "test", symbolSet)) + setSummary.parse() + partialReports[symbolSet] = setSummary + return partialReports + + def _prepareHeadSection(self): + headSection = ''' + <head> + <title>RTEMS coverage report</title> + <style type="text/css"> + progress[value] { + -webkit-appearance: none; + appearance: none; + + width: 150px; + height: 15px; + } + </style> + </head>''' + return headSection + + def _prepareIndexContent(self, partialReports): + header = "<h1> RTEMS coverage analysis report </h1>" + header += "<h3>Coverage reports by symbols sets:</h3>" + table = "<table>" + table += self._headerRow() + for symbolSet in partialReports: + table += self._row(symbolSet, partialReports[symbolSet]) + table += "</table> </br>" + timestamp = "Analysis performed on " + datetime.now().ctime() + return "<body>\n" + header + table + timestamp + "\n</body>" + + def _row(self, symbolSet, summary): + row = "<tr>" + row += "<td>" + symbolSet + "</td>" + row += " <td>" + self._link(summary.indexFilePath,"Index") + "</td>" + row += " <td>" + self._link(summary.summaryFilePath,"Summary") + "</td>" + row += " <td>" + summary.bytes_analyzed + "</td>" + row += " <td>" + summary.bytes_notExecuted + "</td>" + row += " <td>" + summary.ranges_uncovered + "</td>" + row += " <td>" + summary.percentage_executed + "%</td>" + row += " <td>" + summary.percentage_notExecuted + "%</td>" + row += ' <td><progress value="' + summary.percentage_executed + '" max="100"></progress></td>' + row += " <td>" + summary.branches_uncovered + "</td>" + row += " <td>" + summary.branches_total + "</td>" + row += " <td> {:.3%} </td>".format(summary.percentage_branchesCovered) + row += ' <td><progress value="{:.3}" max="100"></progress></td>'.format(100*summary.percentage_branchesCovered) + row += "</tr>\n" + return row + + def _headerRow(self): + row = "<tr>" + row += "<th> Symbols set name </th>" + row += "<th> Index file </th>" + row += "<th> Summary file </th>" + row += "<th> Bytes analyzed </th>" + row += "<th> Bytes not executed </th>" + row += "<th> Uncovered ranges </th>" + row += "<th> Percentage covered </th>" + row += "<th> Percentage uncovered </th>" + row += "<th> Instruction coverage </th>" + row += "<th> Branches uncovered </th>" + row += "<th> Branches total </th>" + row += "<th> Branches covered percentage </th>" + row += "<th> Branches coverage </th>" + row += "</tr>\n" + return row + + def _link(self, address, text): + return '<a href="' + address + '">' + text + '</a>' + + def _createIndexFile(self, headSection, content): + f = open(path.join(self.targetDir, "report.html"),"w") + try: + f.write(headSection) + f.write(content) + finally: + f.close() + + def generate(self): + partialReports = self._findPartialReports() + headSection = self._prepareHeadSection() + indexContent = self._prepareIndexContent(partialReports) + self._createIndexFile(headSection,indexContent) +# _createSummaryFile(summaryContent) + +class covoar(object): + ''' + Covoar runner + ''' + + def __init__(self, baseResultDir, configDir, tracesDir): + self.baseResultDir = baseResultDir + self.configDir = configDir + self.tracesDir = tracesDir + + def run(self, setName, covoarConfigFile, symbolFile): + covoarResultDir = path.join(self.baseResultDir, setName) + + if (not path.exists(covoarResultDir)): + path.mkdir(covoarResultDir) + symbolFile = path.join(self.configDir, symbolFile) + + if (not path.exists(symbolFile)): + log.stderr("Symbol file: " + symbolFile + " doesn't exists! Covoar can not be run!") + log.stderr("Skipping " + setName) + return + + command = "covoar -C" + covoarConfigFile + " -s " + symbolFile + " -O " + covoarResultDir + " " + path.join(self.tracesDir, "*.exe") + log.notice("Running covoar for " + setName, stdout_only=True) + log.notice(command, stdout_only=True) + executor = execute.execute(verbose=True, output=output_handler) + exit_code = executor.shell(command, cwd=os.getcwd()) + status = "success" + if (exit_code != 0): + status = "failure" + log.notice("Coverage run for " + setName + " finished " + status) + log.notice("-----------------------------------------------") + +class coverage_run(object): + ''' + Coverage analysis support for rtems-test + ''' + + def __init__(self, p_targetDir, p_rtdir): + ''' + Constructor + ''' + self.targetDir = p_targetDir + self.testDir = path.join(self.targetDir, "test") + self.covoarConfigPath = path.join(p_rtdir, "config") + self.rtdir = path.abspath(p_rtdir) + self.macros = macros.macros(name=path.join(self.rtdir,'rtems','testing','testing.mc'), rtdir=path.abspath(p_rtdir)) + self.rtscripts = self.macros.expand(self.macros['_rtscripts']) + self.symbolConfigPath = path.join(self.rtscripts, "coverage") + self.tracesDir = path.join(self.targetDir, 'coverage') + self.executables = None + self.symbolSets = [] + + def prepareEnvironment(self): + if(path.exists(self.tracesDir)): + path.removeall(self.tracesDir) + path.mkdir(self.tracesDir) + log.notice("Coverage environment prepared", stdout_only = True) + + + def run(self): + if self.executables == None: + log.stderr("ERROR: Executables for coverage analysis unspecified!") + raise Exception('Executable for coverage analysis unspecified') + + covoarConfigFile = path.join(self.symbolConfigPath, 'config') + if(not path.exists(covoarConfigFile)): + log.stderr("Covoar configuration file: " + path.abspath(covoarConfigFile) + " doesn't exists! Covoar can not be run! "); + return -1 + + self._linkExecutables() + + symbolSetsFile = open(path.join(self.symbolConfigPath,"symbol_sets"), 'r'); + for symbolSet in symbolSetsFile: + setName = symbolSet.split()[0] + symbolFile = symbolSet.split()[1] + self.symbolSets.append(setName) + + covoar_run = covoar(self.testDir, self.symbolConfigPath, self.tracesDir) + covoar_run.run(setName, covoarConfigFile, symbolFile) + + self._generateReports(); + self._cleanup(); + self._summarize(); + + def _linkExecutables(self): + log.notice("Linking executables to " + self.tracesDir) + + for exe in self.executables: + dst = path.join(self.tracesDir, path.basename(exe)) + log.notice("Making symlink from " + exe + " to " + dst) + os.link(exe, dst) + log.notice("Symlinks made") + + def _generateReports(self): + log.notice("Generating reports") + report = reportGen(self.symbolSets, self.targetDir) + report.generate() + + def _cleanup(self): + log.notice("Cleaning workspace up") + path.removeall(self.tracesDir) + + def _summarize(self): + log.notice("Coverage analysis finished. You can find results in " + self.targetDir) + +def output_handler(text): + log.notice(text, stdout_only = True) + +if __name__ == "__main__": + c = coverage_run("/home/rtems/coverage/test_new","/home/rtems/development/rtems/src/rtems-tools/tester") + c.prepareEnvironment() + c.executables = ["/home/rtems/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/testsuites/samples/hello/hello.exe"] + c.run() diff --git a/tester/rt/test.py b/tester/rt/test.py index b0981b4..2be2dd0 100644 --- a/tester/rt/test.py +++ b/tester/rt/test.py @@ -64,6 +64,7 @@ class test(object): if not path.isfile(executable): raise error.general('cannot find executable: %s' % (executable)) self.opts.defaults['test_executable'] = executable + self.opts.defaults['test_executable_name'] = path.basename(executable) if rtems_tools: rtems_tools_bin = path.join(rtems_tools, 'bin') if not path.isdir(rtems_tools_bin): @@ -197,7 +198,7 @@ def run(command_path = None): '--debug-trace': 'Debug trace based on specific flags', '--filter': 'Glob that executables must match to run (default: ' + default_exefilter + ')', - '--stacktrace': 'Dump a stack trace on a user termination (^C)' } + '--stacktrace': 'Dump a stack trace on a user termination (^C)'} opts = options.load(sys.argv, optargs = optargs, command_path = command_path) @@ -220,6 +221,18 @@ def run(command_path = None): rtems_tools = opts.find_arg('--rtems-tools') if rtems_tools: rtems_tools = rtems_tools[1] +# + coverage_enabled = opts.opts['coverage'] + if coverage_enabled: + import coverage + from rtemstoolkit import check + log.notice("Coverage analysis requested") + opts.defaults.load('%%{_configdir}/coverage.mc') + if not check.check_exe('__covoar', opts.defaults['__covoar']): + raise error.general("Covoar not found!") + coverage = coverage.coverage_run(opts.defaults['_cwd'], opts.defaults['_rtdir']) + coverage.prepareEnvironment(); + bsp = opts.find_arg('--rtems-bsp') if bsp is None: raise error.general('no RTEMS BSP provided') @@ -298,6 +311,11 @@ def run(command_path = None): end_time = datetime.datetime.now() log.notice('Average test time: %s' % (str((end_time - start_time) / total))) log.notice('Testing time : %s' % (str(end_time - start_time))) + + if coverage_enabled: + coverage.executables = executables + coverage.run() + except error.general, gerr: print gerr sys.exit(1) diff --git a/tester/rtems/testing/bsps/pc386.mc b/tester/rtems/testing/bsps/pc386.mc new file mode 100644 index 0000000..3a35ebd --- /dev/null +++ b/tester/rtems/testing/bsps/pc386.mc @@ -0,0 +1,57 @@ +# +# RTEMS Tools Project (http://www.rtems.org/) +# Copyright 2010-2014 Chris Johns (chr...@rtems.org) +# All rights reserved. +# +# This file is part of the RTEMS Tools package in 'rtems-tools'. +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER OR 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. +# + +# +# All paths in defaults must be Unix format. Do not store any Windows format +# paths in the defaults. +# +# Every entry must describe the type of checking a host must pass. +# +# Records: +# key: type, attribute, value +# type : none, dir, exe, triplet +# attribute: none, required, optional +# value : 'single line', '''multi line''' +# + +# +# The i386/pc386 QEMU BSP +# + +hda: none, dir, '/home/rtems/qemu/hdtest/rtems-boot.img' + +[global] +bsp: none, none, 'pc386' +coverage_supported: none, none, '1' + +[pc386] +pc386: none, none, '%{_rtscripts}/qemu.cfg' +pc386_arch: none, none, 'i386' +pc386_opts: none, none, '-m 128 -boot b -hda %{hda} %{qemu_opts_base} -append "--console=com1;boot;"' diff --git a/tester/rtems/testing/coverage.mc b/tester/rtems/testing/coverage.mc new file mode 100644 index 0000000..a336cc0 --- /dev/null +++ b/tester/rtems/testing/coverage.mc @@ -0,0 +1,48 @@ +# +# RTEMS Tools Project (http://www.rtems.org/) +# Copyright 2010-2014 Chris Johns (chr...@rtems.org) +# All rights reserved. +# +# This file is part of the RTEMS Tools package in 'rtems-tools'. +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER OR 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. +# + +# +# All paths in defaults must be Unix format. Do not store any Windows format +# paths in the defaults. +# +# Every entry must describe the type of checking a host must pass. +# +# Records: +# key: type, attribute, value +# type : none, dir, exe, triplet +# attribute: none, required, optional +# value : 'single line', '''multi line''' +# + +# +# Global defaults +# +[global] +__covoar: exe, required, 'covoar' diff --git a/tester/rtems/testing/gdb.cfg b/tester/rtems/testing/gdb.cfg index b680dba..5ca344a 100644 --- a/tester/rtems/testing/gdb.cfg +++ b/tester/rtems/testing/gdb.cfg @@ -54,6 +54,13 @@ %define gdb_cmd %{rtems_tools}/%{bsp_arch}-rtems%{rtems_version}-gdb # +# Coverage analysis +# +%if %{_coverage} + %error "Coverage analysis unsupported" +%endif + +# # GDB, pass the GDB command, the text executable and the macro label # for the script. # diff --git a/tester/rtems/testing/qemu.cfg b/tester/rtems/testing/qemu.cfg index a3310bc..2254aef 100644 --- a/tester/rtems/testing/qemu.cfg +++ b/tester/rtems/testing/qemu.cfg @@ -51,7 +51,7 @@ # # Qemu common option patterns. # -%define qemu_opts_base -no-reboot -monitor none -serial stdio -nographic +%define qemu_opts_base -no-reboot -monitor null -serial stdio -nographic %define qemu_opts_no_net -net none # # Qemu executable @@ -60,6 +60,19 @@ %define qemu_opts %{bsp_opts} # +# Coverage analysis +# +%if %{_coverage} + + %if %{coverage_supported} + %define coverage_arg -exec-trace coverage/%{test_executable_name}.cov + %else + %error "Coverage analysis unsupported for %{bsp}" + %endif + +%endif + +# # Executable # -%execute %{qemu_cmd} %{qemu_opts} -kernel %{test_executable} +%execute %{qemu_cmd} %{qemu_opts} -kernel %{test_executable} %{coverage_arg} -- 1.9.1
From 58e79f9d2a3216c4799ac9b8dd4ad34b1ddf5e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 13:18:14 +0200 Subject: [PATCH 02/12] Coverage enabled check fix --- tester/rt/test.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tester/rt/test.py b/tester/rt/test.py index 2be2dd0..a0f98de 100644 --- a/tester/rt/test.py +++ b/tester/rt/test.py @@ -221,18 +221,6 @@ def run(command_path = None): rtems_tools = opts.find_arg('--rtems-tools') if rtems_tools: rtems_tools = rtems_tools[1] -# - coverage_enabled = opts.opts['coverage'] - if coverage_enabled: - import coverage - from rtemstoolkit import check - log.notice("Coverage analysis requested") - opts.defaults.load('%%{_configdir}/coverage.mc') - if not check.check_exe('__covoar', opts.defaults['__covoar']): - raise error.general("Covoar not found!") - coverage = coverage.coverage_run(opts.defaults['_cwd'], opts.defaults['_rtdir']) - coverage.prepareEnvironment(); - bsp = opts.find_arg('--rtems-bsp') if bsp is None: raise error.general('no RTEMS BSP provided') @@ -247,6 +235,18 @@ def run(command_path = None): if not bsp_script: raise error.general('BSP script not found: %s' % (bsp)) bsp_config = opts.defaults.expand(opts.defaults[bsp]) + + coverage_enabled = opts.coverage() + if coverage_enabled: + import coverage + from rtemstoolkit import check + log.notice("Coverage analysis requested") + opts.defaults.load('%%{_configdir}/coverage.mc') + if not check.check_exe('__covoar', opts.defaults['__covoar']): + raise error.general("Covoar not found!") + coverage = coverage.coverage_run(opts.defaults) + coverage.prepareEnvironment(); + report_mode = opts.find_arg('--report-mode') if report_mode: if report_mode[1] != 'failures' and \ @@ -313,6 +313,7 @@ def run(command_path = None): log.notice('Testing time : %s' % (str(end_time - start_time))) if coverage_enabled: + coverage.config_map = opts.defaults.macros['coverage'] coverage.executables = executables coverage.run() -- 1.9.1
From 48496cf896034cb404ad6edb53c264aa489803bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 13:20:15 +0200 Subject: [PATCH 03/12] Files moved from rtems-testing/rtems-coverage --- tester/rtems/testing/coverage/Categories.txt | 19 ++ tester/rtems/testing/coverage/Explanations.txt | 35 ++++ .../coverage/SPARC-Annul-Slot-Explanation.txt | 56 ++++++ tester/rtems/testing/coverage/style.css | 197 +++++++++++++++++++++ 4 files changed, 307 insertions(+) create mode 100644 tester/rtems/testing/coverage/Categories.txt create mode 100644 tester/rtems/testing/coverage/Explanations.txt create mode 100644 tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt create mode 100644 tester/rtems/testing/coverage/style.css diff --git a/tester/rtems/testing/coverage/Categories.txt b/tester/rtems/testing/coverage/Categories.txt new file mode 100644 index 0000000..e19a456 --- /dev/null +++ b/tester/rtems/testing/coverage/Categories.txt @@ -0,0 +1,19 @@ +This is the list of Explanation Categories used when analyzing RTEMS +Coverage report. By using standard categories, the table filter on +the web site works better. + +Simple Test Case + +Hard Test Tase + +Uncalled Routine + +Interrupt Critical Section + +Simple Error Case + +Hard Error Case + +Allocation Error + +Bharath Suri diff --git a/tester/rtems/testing/coverage/Explanations.txt b/tester/rtems/testing/coverage/Explanations.txt new file mode 100644 index 0000000..a5917f6 --- /dev/null +++ b/tester/rtems/testing/coverage/Explanations.txt @@ -0,0 +1,35 @@ +schedulerpriorityyield.c:47 +Simple Test Case +Branch Never Taken +New test where there is more than one thread at a priority with the +executing thread being non-preemptive. Create a higher priority thread +and then yield. + + init task at priority 2, non-preemptive + create task at priority 2 + create task at priority 1 + yield ++++ + +schedulerpriorityyield.c:51 +Simple Test Case +Branch Always Taken +New test where only one thread at a priority (non-preemptive), create a +thread at higher priority, then yield. + + init task at priority 2, non-preemptive + create task at priority 1 + yield ++++ + +schedulerpriorityyield.c:52 +Simple Test Case +Not Executed +Same test case as schedulerpriorityyield.c:51 ++++ + +coremsg.c:86 +Simple Test Case +We need to request enough messages of a certain size that the math +overflows to less than a single message. ++++ diff --git a/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt b/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt new file mode 100644 index 0000000..ef740d3 --- /dev/null +++ b/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt @@ -0,0 +1,56 @@ +The SPARC assembly is often hard to understand because a single +instruction will show up as not executed. The instructions before +and after it will be marked as executed. The instruction before +the one not executed should be a "bxx,a" instruction which means +that the instruction following the branch instruction is executed +ONLY if the branch is taken. Otherwise it is "annulled" or skipped. + +So when you see these cases, it means the branch was NOT taken. + +=================================================================== +Subject: <offlist> annul slot explanation +From: Jiri Gaisler <j...@gaisler.com> +Date: Wed, 3 Jun 2009 14:57:48 -0500 +To: Joel Sherrill <joel.sherr...@oarcorp.com> + + +Joel Sherrill wrote: +> > Hi, +> > +> > I am trying to look at more coverage cases and +> > wanted to make sure I am reading things correctly. +> > +> > The code in question is: +> > +> > +> > if ( the_thread->current_priority > interested_priority ) +> > 200fd00: d8 00 e0 14 ld [ %g3 + 0x14 ], %o4 +> > 200fd04: 80 a3 00 04 cmp %o4, %g4 +> > 200fd08: 38 80 00 1c bgu,a 200fd78 <killinfo+0x224> +> > 200fd0c: 98 10 00 04 mov %g4, +> > %o4 <== NOT EXECUTED +> > +> > /* +> > * If this thread is not interested, then go on to the next thread. +> > */ +> > +> > api = the_thread->API_Extensions[ THREAD_API_POSIX ]; +> > 200fd10: d4 00 e1 6c ld [ %g3 + 0x16c ], %o2 +> > +> > Am I correct in interpreting this as meaning 0x200fd0c +> > is not executed because the bgu,a is never taken. And it +> > is not executed as part of falling through. + +Yes, this is correct. The branch delay slot is only executed +when the branch is taken. + +Jiri. + +> > +> > So in this case we need a test where the "if" condition +> > is true if I am reading things correctly. +> > +> > Thanks. There are a number of these 4 byte cases which +> > are probably easy to hit if I read the code correctly. +> > +> > diff --git a/tester/rtems/testing/coverage/style.css b/tester/rtems/testing/coverage/style.css new file mode 100644 index 0000000..c715518 --- /dev/null +++ b/tester/rtems/testing/coverage/style.css @@ -0,0 +1,197 @@ +body { + background: rgb(253,253,253); + color: rgb(0,0,0); + font-family: helvetica, sans-serif; + font-size: 1em; + line-height: 1.4; + margin: 5px, 5px, 5px, 5px; + padding: 0; +} + +a:link { + color: rgb(180, 50, 50); + font-family: helvetica, sans-serif; + font-size: 1.0em; +} + +a:visited { + color: purple; + font-family: helvetica, sans-serif; + font-size: 1.0em; +} + +a:hover { + color: rgb(0, 0, 0); + font-family: helvetica, sans-serif; + font-size: 1.0em; +} + +a:active { + color: red; + font-family: helvetica, sans-serif; + font-size: 1.0em; +} + +.heading { + background: rgb(250,250,250); + background-image: url("http://www.rtems.org/logos/rtems_logo.jpg"); + background-repeat: no-repeat; + color: rgb(55,55,55); + font-size: 1.5em; + height: 140px; + padding-top: 20px; + padding-left: 300px; +} + +.heading-title { + text-align: center; + color: rgb(0,0,0); + font-size: 0.9em; + font-weight: bold; + padding-top: 5px; + padding-left: 0px; + text-align: center; + width: 100%; +} + +.datetime { + color: rgb(55,55,55); + font-size: 0.8em; + padding-top: 5px; + padding-left: 0px; + text-align: center; + width: 100%; +} + +.info { + color: rgb(55,55,55); + font-size: 0.6em; + padding-top: 5px; + padding-left: 00px; + text-align: center; + width: 100%; +} + +.stats-table { + background: rgb(225,225,225); + font-size: 0.9em; + border: 1px solid rgb(200, 200, 200); + padding: 0; + margin-top: 3px; + margin-left: 10px; + width: 70%; +} + +.stats-table-target { + background: rgb(243,243,243); + font-size: 1.2em; + padding-left: 10px; + text-align: left; +} + +.stats-target-results { + background: rgb(243,243,243); + font-size: 0.9em; + text-align: right; + padding-right: 10px; +} + +.stats-target-good { + background: rgb(30,230,30); + font-size: 0.9em; + text-align: right; + padding-right: 10px; +} + +.stats-target-good { + background: rgb(50,180,50); + color: rgb(230,230,230); + font-size: 0.9em; + text-align: center; + padding-right: 10px; +} + +.stats-target-bad { + background: rgb(180,50,50); + color: rgb(230,230,230); + font-size: 0.9em; + text-align: center; + padding-right: 10px; +} + +.stats-table-top { + background: rgb(243,243,243); + color: rgb(0,0,0); + font-size: 0.9em; + padding-left: 2px; +} + +.stats-table-row { + background: rgb(253,253,253); + font-size: 0.9em; + padding: 1px; + text-align: right; +} + +.error-table { + font-size: 0.9em; + border: 1px solid rgb(200, 200, 200); + padding: 0; + margin-left: 10px; + width: 96%; +} + +.error-table-top { + background: rgb(225,225,225); + color: rgb(0,0,0); + font-size: 0.9em; + padding-left: 2px; +} + +.error-table-on { + background: rgb(225,225,225); + font-size: 0.9em; + padding-left: 2px; +} + +.error-table-off { + background: rgb(253,253,253); + font-size: 0.9em; + padding-left: 2px; +} + +.error-table-dups { + text-align: right; + padding-right: 2px; +} + +.error-table-error { + background: rgb(255,150,150); + font-size: 0.9em; + padding-left: 2px; +} + +.error-table-warning { + font-size: 0.9em; + padding-left: 2px; +} + +.navbar { + margin-left: auto; + margin-right: auto; + margin-top: 10px; + width: 40%; +} +th.table-sortable { + background-image:url("unsorted.gif"); + cursor: pointer; + background-position: center left; + background-repeat: no-repeat; + padding-left: 15px; +} +th.table-sorted-asc { + background-image:url("descending.gif"); +} +th.table-sorted-desc { + background-image:url("ascending.gif"); +} \ No newline at end of file -- 1.9.1
From 94cc111ad1c61982c8333d743fb940b7c1eb242c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 13:21:21 +0200 Subject: [PATCH 04/12] Qemu rtems-boot.img binary for pc386 booting added --- tester/rtems/testing/coverage/rtems-boot.img | Bin 0 -> 5242880 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tester/rtems/testing/coverage/rtems-boot.img diff --git a/tester/rtems/testing/coverage/rtems-boot.img b/tester/rtems/testing/coverage/rtems-boot.img new file mode 100644 index 0000000000000000000000000000000000000000..3995316735a53542acdf0d92e0b725fe296c0b49 GIT binary patch literal 5242880 zcmeFtfdBvi0Dz$VsTV1P3IhfV7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjxE(qc00000802p~h`oi7 z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ S0|pEjFkrxd0RsjMoPhuYumAx7 literal 0 HcmV?d00001 -- 1.9.1
From 261d1c2bc502754d35bd4153ee3157f537816f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 13:26:18 +0200 Subject: [PATCH 05/12] Symbol generation added to covoar --- tester/covoar/SymbolSet.cpp | 111 ++++++++++++++++++++++++++++++++++++++ tester/covoar/SymbolSet.h | 51 ++++++++++++++++++ tester/covoar/SymbolSetReader.cpp | 82 ++++++++++++++++++++++++++++ tester/covoar/SymbolSetReader.h | 34 ++++++++++++ tester/covoar/covoar.cc | 32 +++++++++-- tester/covoar/wscript | 25 +++++++-- 6 files changed, 327 insertions(+), 8 deletions(-) create mode 100644 tester/covoar/SymbolSet.cpp create mode 100644 tester/covoar/SymbolSet.h create mode 100644 tester/covoar/SymbolSetReader.cpp create mode 100644 tester/covoar/SymbolSetReader.h diff --git a/tester/covoar/SymbolSet.cpp b/tester/covoar/SymbolSet.cpp new file mode 100644 index 0000000..c8f83e5 --- /dev/null +++ b/tester/covoar/SymbolSet.cpp @@ -0,0 +1,111 @@ +/* + * SymbolSet.cpp + * + * Created on: Aug 5, 2014 + * Author: Krzysztof MiÄsowicz <krzysztof.miesow...@gmail.com> + */ + +#include "SymbolSet.h" +#include "rld-process.h" +#include "rld.h" +#include <iostream> +#include <fstream> +#include <cstdio> + +namespace Symbols { + +SymbolSet::SymbolSet() { + // TODO Auto-generated constructor stub + +} + +SymbolSet::~SymbolSet() { + // TODO Auto-generated destructor stub +} + +std::string SymbolSet::parseNmOutputLine(std::string line) { + std::cout << "Read: " << std::endl; + std::cout << line << std::endl; + std::cout << "--------" << std::endl; + std::string symbol = ""; + if (line.find("FUNC|") != std::string::npos) { + std::cout << "Function:" << std::endl; + symbol = line.substr(0, line.find('|')); + std::cout << symbol << std::endl; + } else { + std::cout << "Not a function" << std::endl; + } + return symbol; +} + +std::string SymbolSet::getLibname(std::string libPath) { + std::string libname = "", base = "", temp; + size_t pos = libPath.find_last_of('/'); + if (pos != std::string::npos) { + temp = libPath.substr(0, pos); + libname = libPath.substr(pos + 1); + } + pos = temp.find_last_of('/'); + if (pos != std::string::npos) { + base = temp.substr(pos + 1); + } + + return base + "/" + libname; +} + +void SymbolSet::parseNmOutput(std::ifstream& nm_out, const std::string& lib) { + std::string line, symbol; + while (getline(nm_out, line)) { + symbol = parseNmOutputLine(line); + if (symbol.length() > 0) { + symbols.push_back(symbol + " " + getLibname(lib)); + } + } +} + +void SymbolSet::generateSymbolFile(std::string filePath, std::string target) { + std::cout << __FUNCTION__ << "(): arguments: " << filePath << ", " << target << std::endl; + std::string nm_output = "nm.out"; + std::string nm_error = "nm.err"; + std::string libFiles; + + for (std::string lib : libraries) { + try { + auto status = rld::process::execute(target + "-nm", + std::vector<std::string> { target + "-nm", "--format=sysv", + lib }, nm_output, nm_error); + if (status.type != rld::process::status::normal + or + status.code != 0) { + std::cout << "ERROR: nm returned " << status.code << std::endl; + std::cout << "For details see " << nm_error << " file." << std::endl; + std::remove(nm_output.c_str()); + return; + } + + } catch (rld::error& err) { + std::cout << "Error while running nm for " + lib << std::endl; + std::cout << err.what << " in " << err.where << std::endl; + return; + } + + std::ifstream nm_out(nm_output); + try { + parseNmOutput(nm_out, lib); + } catch(std::exception& e) { + std::cout << "ERROR while parsing nm output: " << e.what() << std::endl; + } + nm_out.close(); + } + + std::remove(nm_output.c_str()); + std::remove(nm_error.c_str()); + + std::ofstream outputFile(filePath); + for (std::string symbol : symbols) { + outputFile << symbol << std::endl; + } + outputFile.close(); +} + +} /* namespace Symbols */ diff --git a/tester/covoar/SymbolSet.h b/tester/covoar/SymbolSet.h new file mode 100644 index 0000000..54e925d --- /dev/null +++ b/tester/covoar/SymbolSet.h @@ -0,0 +1,51 @@ +/* + * SymbolSet.h + * + * Created on: Aug 5, 2014 + * Author: Krzysztof MiÄsowicz <krzysztof.miesow...@gmail.com> + */ + +#ifndef SYMBOLSET_H_ +#define SYMBOLSET_H_ + +#include <string> +#include <vector> + +namespace Symbols { + +class SymbolSet { +public: + SymbolSet(); + virtual ~SymbolSet(); + + const std::string getName() const { + return name; + } + + void setName(const std::string& name) { + this->name = name; + } + + const std::vector<std::string> getLibraries() const { + return libraries; + } + + void addLibrary(std::string libraryPath) { + libraries.push_back(libraryPath); + } + + void generateSymbolFile(std::string filePath, std::string target); + +private: + std::string name; + std::vector<std::string> libraries; + std::vector<std::string> symbols; + + std::string parseNmOutputLine(std::string line); + std::string getLibname(std::string libPath); + void parseNmOutput(std::ifstream& nm_out, const std::string& lib); +}; + +} /* namespace Symbols */ + +#endif /* SYMBOLSET_H_ */ diff --git a/tester/covoar/SymbolSetReader.cpp b/tester/covoar/SymbolSetReader.cpp new file mode 100644 index 0000000..886e256 --- /dev/null +++ b/tester/covoar/SymbolSetReader.cpp @@ -0,0 +1,82 @@ +/* + * SymbolSetReader.cpp + * + * Created on: Aug 5, 2014 + * Author: Krzysztof MiÄsowicz <krzysztof.miesow...@gmail.com> + */ + +#include "SymbolSetReader.h" +#include "iostream" +#include "fstream" + +namespace Symbols { + +SymbolSetReader::SymbolSetReader() { + // TODO Auto-generated constructor stub + +} + +SymbolSetReader::~SymbolSetReader() { + // TODO Auto-generated destructor stub +} + +std::vector<SymbolSet> SymbolSetReader::readSetFile(string filepath) { + std::vector<SymbolSet> setList { }; + ifstream file(filepath); + string line; + while (getline(file, line)) { + if (line.find("symbolset:") != std::string::npos) { + setList.emplace_back(); + } else if (line.length() > 0) { + + auto pair = parseLine(line); + + if(pair.first == "name") { + if (setList.empty()) { + setList.emplace_back(); + } + setList.rbegin()->setName(pair.second); + continue; + } + if(pair.first == "lib") { + setList.rbegin()->addLibrary(pair.second); + continue; + } + + std::cout << "Invalid entry in configuration file : " << line << endl; + break; + } + } + file.close(); + return setList; +} + +std::pair<string, string> SymbolSetReader::parseLine(string line) { + size_t delimeterPosition = line.find('='); + + if (delimeterPosition != std::string::npos) { + string key = line.substr(0, delimeterPosition); + string value = line.substr(delimeterPosition + 1); + return {trim(key), trim(value)}; + } + + return {"",""}; +} + +string& SymbolSetReader::trim(string& str) { + // trim trailing spaces + size_t endpos = str.find_last_not_of(" \t\n\r"); + if (string::npos != endpos) { + str = str.substr(0, endpos + 1); + } + + // trim leading spaces + size_t startpos = str.find_first_not_of(" \t\n\r"); + if (string::npos != startpos) { + str = str.substr(startpos); + } + + return str; +} + +} /* namespace Symbols */ diff --git a/tester/covoar/SymbolSetReader.h b/tester/covoar/SymbolSetReader.h new file mode 100644 index 0000000..24e83cf --- /dev/null +++ b/tester/covoar/SymbolSetReader.h @@ -0,0 +1,34 @@ +/* + * SymbolSetReader.h + * + * Created on: Aug 5, 2014 + * Author: Krzysztof MiÄsowicz <krzysztof.miesow...@gmail.com> + */ + +#ifndef SYMBOLSETREADER_H_ +#define SYMBOLSETREADER_H_ + +#include <string> +#include <vector> +#include <utility> +#include "SymbolSet.h" + +using namespace std; + +namespace Symbols { + +class SymbolSetReader { +public: + SymbolSetReader(); + virtual ~SymbolSetReader(); + + vector<SymbolSet> readSetFile(string filepath); +protected: + pair<string, string> parseLine(string line); +private: + string& trim(string& str); +}; + +} /* namespace Symbols */ + +#endif /* SYMBOLSETREADER_H_ */ diff --git a/tester/covoar/covoar.cc b/tester/covoar/covoar.cc index 78954fd..868f40d 100644 --- a/tester/covoar/covoar.cc +++ b/tester/covoar/covoar.cc @@ -23,6 +23,9 @@ #include "TargetFactory.h" #include "GcovData.h" +#include "SymbolSetReader.h" +#include "SymbolSet.h" + /* * Variables to control general behavior */ @@ -38,6 +41,7 @@ std::list<Coverage::ExecutableInfo*> executablesToAnalyze; const char* explanations = NULL; char* progname; const char* symbolsFile = NULL; +const char* symbolSetFile = NULL; const char* gcnosFileName = NULL; char gcnoFileName[FILE_NAME_LENGTH]; char gcdaFileName[FILE_NAME_LENGTH]; @@ -64,6 +68,7 @@ void usage() "(RTEMS, QEMU, TSIM or Skyeye)\n" " -E EXPLANATIONS - name of file with explanations\n" " -s SYMBOLS_FILE - name of file with symbols of interest\n" + " -S SYMBOL_SET_FILE - name of file specifying symbol set of interest\n" " -1 EXECUTABLE - name of executable to get symbols from\n" " -e EXE_EXTENSION - extension of the executables to analyze\n" " -c COVERAGEFILE_EXTENSION - extension of the coverage files to analyze\n" @@ -89,6 +94,7 @@ Configuration::Options_t Options[] = { { "explanations", NULL }, { "format", NULL }, { "symbolsFile", NULL }, + { "symbolSetFile", NULL }, { "outputDirectory", NULL }, { "executableExtension", NULL }, { "coverageExtension", NULL }, @@ -166,7 +172,7 @@ int main( // progname = argv[0]; - while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:T:O:p:v")) != -1) { + while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:S:T:O:p:v")) != -1) { switch (opt) { case 'C': CoverageConfiguration->processFile( optarg ); break; case '1': singleExecutable = optarg; break; @@ -177,6 +183,7 @@ int main( case 'E': explanations = optarg; break; case 'f': format = optarg; break; case 's': symbolsFile = optarg; break; + case 'S': symbolSetFile = optarg; break; case 'T': target = optarg; break; case 'O': outputDirectory = optarg; break; case 'v': Verbose = true; break; @@ -337,8 +344,8 @@ int main( } // Validate that we have a symbols of interest file. - if (!symbolsFile) { - fprintf( stderr, "ERROR: symbols of interest file not specified\n" ); + if (!symbolsFile && !symbolSetFile) { + fprintf( stderr, "ERROR: neither symbols of interest file nor symbol set file not specified\n" ); usage(); exit(-1); } @@ -352,7 +359,24 @@ int main( // Create the set of desired symbols. SymbolsToAnalyze = new Coverage::DesiredSymbols(); - SymbolsToAnalyze->load( symbolsFile ); + + //Load symbols from specified symbolsFile + if(symbolsFile) { + SymbolsToAnalyze->load( symbolsFile ); + } + + //Read symbol configuration file and load needed symbols + if(symbolSetFile) { + cout << "Reading symbols sets configuration for symbol set file: " << symbolSetFile << endl; + Symbols::SymbolSetReader ssr; + std::vector<Symbols::SymbolSet> symbolSets = ssr.readSetFile(symbolSetFile); + + Symbols::SymbolSet& set = symbolSets[0]; + cout << "Generating symbol file for " << set.getName() << endl; + set.generateSymbolFile(set.getName() + ".syms", target); + SymbolsToAnalyze->load((set.getName() + ".syms").c_str()); + } + if (Verbose) fprintf( stderr, diff --git a/tester/covoar/wscript b/tester/covoar/wscript index 88add6e..5b72c34 100644 --- a/tester/covoar/wscript +++ b/tester/covoar/wscript @@ -46,6 +46,16 @@ APPNAME='covoar' top = '.' out = 'build' +# +# Paths to rtl-host +# +rtl_host_build_dir = "./../../rtl-host/build-linux2" +rtl_host_dir = "./../../rtl-host" +rtl_includes = ['../../rtl-host', + '../../rtl-host/elftoolchain/common', + '../../rtl-host/elftoolchain/libelf', + '../../rtl-host/libiberty'] + def options(opt): opt.load('compiler_cxx') @@ -54,8 +64,11 @@ def configure(conf): conf.check_cc(function_name='open64', header_name="stdlib.h", mandatory = False) conf.check_cc(function_name='stat64', header_name="stdlib.h", mandatory = False) conf.write_config_header('covoar-config.h') + conf.env.STLIBPATH_RLD = conf.path.abspath() + rtl_host_build_dir + conf.env.STLIB_RLD = ['rld','iberty','elf'] def build(bld): + bld.stlib(target = 'ccovoar', source = ['app_common.cc', 'ConfigFile.cc', @@ -89,9 +102,13 @@ def build(bld): 'Target_lm32.cc', 'Target_m68k.cc', 'Target_powerpc.cc', - 'Target_sparc.cc'], + 'Target_sparc.cc', + 'SymbolSet.cpp', + 'SymbolSetReader.cpp'], cflags = ['-O2', '-g'], - includes = ['.']) + cxxflags = ['-std=c++11', '-O2', '-g'], + includes = ['.', + './symbolGen'] + rtl_includes) bld.program(target = 'trace-converter', source = ['TraceConverter.cc', @@ -106,12 +123,12 @@ def build(bld): bld.program(target = 'covoar', source = ['covoar.cc'], - use = 'ccovoar', + use = ['ccovoar','RLD'], cflags = ['-O2', '-g'], includes = ['.']) bld.program(target = 'covoar', source = ['covoar.cc'], - use = 'ccovoar', + use = ['ccovoar','RLD'], cflags = ['-O2', '-g'], includes = ['.']) -- 1.9.1
From 27ce4052970cf86b97f7bd1d266be02324ee82d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:09:08 +0200 Subject: [PATCH 06/12] Creating covoar config file from coverage module, interface with symbol generation in covoar, covoar exit status check fix --- tester/rt/coverage.py | 146 +++++++++++++++++++++++++++++++------ tester/rtems/testing/bsps/pc386.mc | 11 ++- 2 files changed, 132 insertions(+), 25 deletions(-) diff --git a/tester/rt/coverage.py b/tester/rt/coverage.py index e170607..cb5ea33 100644 --- a/tester/rt/coverage.py +++ b/tester/rt/coverage.py @@ -7,6 +7,7 @@ from rtemstoolkit import path from rtemstoolkit import log from rtemstoolkit import execute from rtemstoolkit import macros +import shutil import os from datetime import datetime @@ -148,36 +149,114 @@ class reportGen: self._createIndexFile(headSection,indexContent) # _createSummaryFile(summaryContent) +class symbolsConfiguration(object): + ''' + Manages symbols configuration - reading from symbol file + ''' + def __init__(self): + self.symbolSets = [] + + def _log_invalid_format(self): + log.stderr("Invalid symbol configuration file") + log.stderr(''' Configuration file format: + symbolset: + name=SYMBOLSET_NAME + lib=PATH_TO_LIBRARY_1 + lib=PATH_TO_LIBRARY_2 + symbolset: + name=SYMBOLSET_NAME_N + lib=PATH_TO_LIBRARY ''') + + def load(self, symbolSetConfigFile): + scf = open(symbolSetConfigFile, 'r') + for line in scf: + try: + if line.strip().startswith("symbolset"): + self.symbolSets.append(symbolSet("",[])) + else: + splitted = line.split('=') + if(len(splitted) == 2): + key = splitted[0].strip() + value = splitted[1].strip() + if key == 'name': + self.symbolSets[-1].name = value + elif key == 'lib': + self.symbolSets[-1].libs.append(value) + else: + log.stderr("Invalid key : " + key + " in symbol set configuration file " + symbolSetConfigFile) + else: + self._log_invalid_format() + except: + self._log_invalid_format() + scf.close() + + def save(self, path): + scf = open(path, 'w') + for sset in self.symbolSets: + sset.writeSetFile(path) + scf.close() + +class symbolSet(object): + def __init__(self, name, libs): + self.name = name + self.libs = libs + + def isValid(self): + if len(self.name) == 0: + log.stderr("Invalid symbol set. Symbol set must have name! ") + return False + if len(self.libs) == 0: + log.stderr("Invalid symbol set. Symbol set must have specified libraries!") + return False + for lib in self.libs: + if not path.exists(lib): + log.stderr("Invalid library path: " + lib) + return False + return True + + def writeSetFile(self, path): + f = open(path, 'w') + f.write("symbolset:\n") + f.write("\t name=" + self.name + '\n') + for lib in self.libs: + f.write("\t lib=" + lib + '\n') + f.close() + class covoar(object): ''' Covoar runner ''' - def __init__(self, baseResultDir, configDir, tracesDir): + def __init__(self, baseResultDir, configDir, tracesDir, covoarSrcDir): self.baseResultDir = baseResultDir self.configDir = configDir self.tracesDir = tracesDir + self.covoarSrcDir = covoarSrcDir def run(self, setName, covoarConfigFile, symbolFile): covoarResultDir = path.join(self.baseResultDir, setName) if (not path.exists(covoarResultDir)): path.mkdir(covoarResultDir) - symbolFile = path.join(self.configDir, symbolFile) if (not path.exists(symbolFile)): - log.stderr("Symbol file: " + symbolFile + " doesn't exists! Covoar can not be run!") + log.stderr("Symbol set file: " + symbolFile + " doesn't exists! Covoar can not be run!") log.stderr("Skipping " + setName) return - command = "covoar -C" + covoarConfigFile + " -s " + symbolFile + " -O " + covoarResultDir + " " + path.join(self.tracesDir, "*.exe") + command = "covoar -C" + covoarConfigFile + " -S " + symbolFile + " -O " + covoarResultDir + " " + path.join(self.tracesDir, "*.exe") log.notice("Running covoar for " + setName, stdout_only=True) log.notice(command, stdout_only=True) executor = execute.execute(verbose=True, output=output_handler) exit_code = executor.shell(command, cwd=os.getcwd()) + + shutil.copy2(path.join(self.covoarSrcDir, 'table.js'), path.join(covoarResultDir, 'table.js')) + shutil.copy2(path.join(self.covoarSrcDir, 'covoar.css'), path.join(covoarResultDir, 'covoar.css')) + + log.notice("Coverage run for " + setName + " finished ") status = "success" - if (exit_code != 0): - status = "failure" + if (exit_code[0] != 0): + status = "failure. Error code: " + str(exit_code[0]) log.notice("Coverage run for " + setName + " finished " + status) log.notice("-----------------------------------------------") @@ -186,18 +265,19 @@ class coverage_run(object): Coverage analysis support for rtems-test ''' - def __init__(self, p_targetDir, p_rtdir): + def __init__(self, p_macros): ''' Constructor ''' - self.targetDir = p_targetDir + self.macros = p_macros + self.targetDir = self.macros['_cwd'] self.testDir = path.join(self.targetDir, "test") - self.covoarConfigPath = path.join(p_rtdir, "config") - self.rtdir = path.abspath(p_rtdir) - self.macros = macros.macros(name=path.join(self.rtdir,'rtems','testing','testing.mc'), rtdir=path.abspath(p_rtdir)) + self.rtdir = path.abspath(self.macros['_rtdir']) self.rtscripts = self.macros.expand(self.macros['_rtscripts']) - self.symbolConfigPath = path.join(self.rtscripts, "coverage") + self.coverageConfigPath = path.join(self.rtscripts, "coverage") + self.symbolConfigPath = path.join(self.coverageConfigPath, "symbolSets.config") self.tracesDir = path.join(self.targetDir, 'coverage') + self.config_map = self.macros.macros['coverage'] self.executables = None self.symbolSets = [] @@ -207,27 +287,46 @@ class coverage_run(object): path.mkdir(self.tracesDir) log.notice("Coverage environment prepared", stdout_only = True) + def writeCovoarConfig(self, covoarConfigFile): + ccf = open(covoarConfigFile, 'w') + ccf.write("format = " + self.config_map['format'][2] + '\n') + ccf.write("target = " + self.config_map['target'][2] + '\n') + ccf.write("explanations = " + self.macros.expand(self.config_map['explanations'][2]) + '\n') + ccf.write("coverageExtension = " + self.config_map['coverageextension'][2] + '\n') + ccf.write("gcnosFile = " + self.macros.expand(self.config_map['gcnosfile'][2]) + '\n') + ccf.write("executableExtension = " + self.config_map['executableextension'][2] + '\n') + ccf.write("projectName = " + self.config_map['projectname'][2] + '\n') + ccf.close() def run(self): if self.executables == None: log.stderr("ERROR: Executables for coverage analysis unspecified!") raise Exception('Executable for coverage analysis unspecified') + if self.config_map == None: + log.stderr("ERROR: Configuration map for coverage analysis unspecified!") + raise Exception("ERROR: Configuration map for coverage analysis unspecified!") - covoarConfigFile = path.join(self.symbolConfigPath, 'config') + covoarConfigFile = path.join(self.tracesDir, 'config') + self.writeCovoarConfig(covoarConfigFile) if(not path.exists(covoarConfigFile)): log.stderr("Covoar configuration file: " + path.abspath(covoarConfigFile) + " doesn't exists! Covoar can not be run! "); return -1 self._linkExecutables() - symbolSetsFile = open(path.join(self.symbolConfigPath,"symbol_sets"), 'r'); - for symbolSet in symbolSetsFile: - setName = symbolSet.split()[0] - symbolFile = symbolSet.split()[1] - self.symbolSets.append(setName) + symbolConfig = symbolsConfiguration() + symbolConfig.load(self.symbolConfigPath) + + for sset in symbolConfig.symbolSets: + if sset.isValid(): + symbolSetFile = path.join(self.tracesDir, sset.name + ".symcfg") + sset.writeSetFile(symbolSetFile) + self.symbolSets.append(sset.name) - covoar_run = covoar(self.testDir, self.symbolConfigPath, self.tracesDir) - covoar_run.run(setName, covoarConfigFile, symbolFile) + covoar_run = covoar(self.testDir, self.symbolConfigPath, self.tracesDir, path.join(self.rtdir, 'covoar')) + covoar_run.run(sset.name, covoarConfigFile, symbolSetFile) + else: + log.stderr("Invalid symbol set " + sset.name + ". Skipping covoar run.") self._generateReports(); self._cleanup(); @@ -238,7 +337,6 @@ class coverage_run(object): for exe in self.executables: dst = path.join(self.tracesDir, path.basename(exe)) - log.notice("Making symlink from " + exe + " to " + dst) os.link(exe, dst) log.notice("Symlinks made") @@ -255,10 +353,10 @@ class coverage_run(object): log.notice("Coverage analysis finished. You can find results in " + self.targetDir) def output_handler(text): - log.notice(text, stdout_only = True) + log.notice(text, stdout_only = False) if __name__ == "__main__": - c = coverage_run("/home/rtems/coverage/test_new","/home/rtems/development/rtems/src/rtems-tools/tester") + c = coverage_run("/home/krzysztof/coverage/kmtest","/home/krzysztof/development/rtems/src/rtems-tools/tester") c.prepareEnvironment() - c.executables = ["/home/rtems/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/testsuites/samples/hello/hello.exe"] + c.executables = ["/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/testsuites/samples/hello/hello.exe"] c.run() diff --git a/tester/rtems/testing/bsps/pc386.mc b/tester/rtems/testing/bsps/pc386.mc index 3a35ebd..9418c00 100644 --- a/tester/rtems/testing/bsps/pc386.mc +++ b/tester/rtems/testing/bsps/pc386.mc @@ -45,7 +45,7 @@ # The i386/pc386 QEMU BSP # -hda: none, dir, '/home/rtems/qemu/hdtest/rtems-boot.img' +hda: none, dir, '%{_rtscripts}/coverage/rtems-boot.img' [global] bsp: none, none, 'pc386' @@ -55,3 +55,12 @@ coverage_supported: none, none, '1' pc386: none, none, '%{_rtscripts}/qemu.cfg' pc386_arch: none, none, 'i386' pc386_opts: none, none, '-m 128 -boot b -hda %{hda} %{qemu_opts_base} -append "--console=com1;boot;"' + +[coverage] +format: none, none, 'QEMU' +target: none, none, 'i386-rtems4.11' +explanations: none, none, '%{_rtscripts}/coverage/Explanations.txt' +coverageExtension: none, none, 'exe.cov' +gcnosFile: none, none, '%{_rtscripts}/coverage/rtems.gcnos' +executableExtension: none, none, 'exe' +projectName: none, none, 'RTEMS 4.11' -- 1.9.1
From aa83acdf4d205278caa9f3a8ba7774cb274bae85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:11:16 +0200 Subject: [PATCH 07/12] Fix in qemu.cfg for runs without coverage --- tester/rtems/testing/qemu.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tester/rtems/testing/qemu.cfg b/tester/rtems/testing/qemu.cfg index 2254aef..9ff9014 100644 --- a/tester/rtems/testing/qemu.cfg +++ b/tester/rtems/testing/qemu.cfg @@ -62,7 +62,8 @@ # # Coverage analysis # -%if %{_coverage} +%define coverage_arg +%if %{defined _coverage} %if %{coverage_supported} %define coverage_arg -exec-trace coverage/%{test_executable_name}.cov -- 1.9.1
From 60b4d352e9355e4f0aef3a85447a2cf4baf14859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:11:52 +0200 Subject: [PATCH 08/12] Coverage option getter added --- rtemstoolkit/options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtemstoolkit/options.py b/rtemstoolkit/options.py index 5aa1ed3..5ddd3c8 100644 --- a/rtemstoolkit/options.py +++ b/rtemstoolkit/options.py @@ -406,6 +406,9 @@ class command_line(object): def no_install(self): return self.opts['no-install'] != '0' + def coverage(self): + return self.opts['coverage'] != '0' + def user_macros(self): # # Return something even if it does not exist. -- 1.9.1
From 3f2821dc17a944be009c3afdc5e42b787eb073e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:12:50 +0200 Subject: [PATCH 09/12] Buffer overflow during writing annotated report fixed --- tester/covoar/ReportsBase.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tester/covoar/ReportsBase.cc b/tester/covoar/ReportsBase.cc index d401bdd..2b6b8c9 100644 --- a/tester/covoar/ReportsBase.cc +++ b/tester/covoar/ReportsBase.cc @@ -205,7 +205,8 @@ void ReportsBase::WriteAnnotatedReport( uint32_t id = 0; std::string annotation = ""; std::string line; - char textLine[150]; + const std::size_t LINE_LENGTH = 150; + char textLine[LINE_LENGTH]; state = A_SOURCE; @@ -228,7 +229,7 @@ void ReportsBase::WriteAnnotatedReport( } } - sprintf( textLine, "%-70s", itr->line.c_str() ); + snprintf( textLine, LINE_LENGTH, "%-70s", itr->line.c_str() ); line = textLine + annotation; PutAnnotatedLine( aFile, state, line, id); -- 1.9.1
From 464b01755734ca17be10d354ff6a4edacbfd4d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:28:48 +0200 Subject: [PATCH 10/12] Failure handling added to report generation --- tester/rt/coverage.py | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tester/rt/coverage.py b/tester/rt/coverage.py index cb5ea33..971d3cf 100644 --- a/tester/rt/coverage.py +++ b/tester/rt/coverage.py @@ -25,10 +25,12 @@ class summary: self.branches_alwaysTaken = 0 self.branches_neverTaken = 0 self.percentage_branchesCovered = 0.0 + self.isFailure = False def parse(self): if(not path.exists(self.summaryFilePath)): log.warning("Summary file " + self.summaryFilePath + " does not exist!") + self.isFailure = True return summaryFile = open(self.summaryFilePath,'r') @@ -59,6 +61,7 @@ class reportGen: self.symbolSetsList = p_symbolSetsList self.targetDir = p_targetDir self.partialReportsFiles = list(["index.html", "summary.txt"]) + self.numberOfColumns = 1 def _findPartialReports(self): partialReports = {} @@ -98,19 +101,22 @@ class reportGen: def _row(self, symbolSet, summary): row = "<tr>" row += "<td>" + symbolSet + "</td>" - row += " <td>" + self._link(summary.indexFilePath,"Index") + "</td>" - row += " <td>" + self._link(summary.summaryFilePath,"Summary") + "</td>" - row += " <td>" + summary.bytes_analyzed + "</td>" - row += " <td>" + summary.bytes_notExecuted + "</td>" - row += " <td>" + summary.ranges_uncovered + "</td>" - row += " <td>" + summary.percentage_executed + "%</td>" - row += " <td>" + summary.percentage_notExecuted + "%</td>" - row += ' <td><progress value="' + summary.percentage_executed + '" max="100"></progress></td>' - row += " <td>" + summary.branches_uncovered + "</td>" - row += " <td>" + summary.branches_total + "</td>" - row += " <td> {:.3%} </td>".format(summary.percentage_branchesCovered) - row += ' <td><progress value="{:.3}" max="100"></progress></td>'.format(100*summary.percentage_branchesCovered) - row += "</tr>\n" + if summary.isFailure: + row += ' <td colspan="' + str(self.numberOfColumns-1) + '" style="background-color:red">FAILURE</td>' + else: + row += " <td>" + self._link(summary.indexFilePath,"Index") + "</td>" + row += " <td>" + self._link(summary.summaryFilePath,"Summary") + "</td>" + row += " <td>" + summary.bytes_analyzed + "</td>" + row += " <td>" + summary.bytes_notExecuted + "</td>" + row += " <td>" + summary.ranges_uncovered + "</td>" + row += " <td>" + summary.percentage_executed + "%</td>" + row += " <td>" + summary.percentage_notExecuted + "%</td>" + row += ' <td><progress value="' + summary.percentage_executed + '" max="100"></progress></td>' + row += " <td>" + summary.branches_uncovered + "</td>" + row += " <td>" + summary.branches_total + "</td>" + row += " <td> {:.3%} </td>".format(summary.percentage_branchesCovered) + row += ' <td><progress value="{:.3}" max="100"></progress></td>'.format(100*summary.percentage_branchesCovered) + row += "</tr>\n" return row def _headerRow(self): @@ -129,6 +135,7 @@ class reportGen: row += "<th> Branches covered percentage </th>" row += "<th> Branches coverage </th>" row += "</tr>\n" + self.numberOfColumns = row.count('<th>') return row def _link(self, address, text): -- 1.9.1
From ccb283f513dfc122d515ec054a40e250a58735d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 14:29:47 +0200 Subject: [PATCH 11/12] Debug logging statement removed --- tester/covoar/SymbolSet.cpp | 8 -------- tester/covoar/covoar.cc | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/tester/covoar/SymbolSet.cpp b/tester/covoar/SymbolSet.cpp index c8f83e5..8290949 100644 --- a/tester/covoar/SymbolSet.cpp +++ b/tester/covoar/SymbolSet.cpp @@ -24,16 +24,9 @@ SymbolSet::~SymbolSet() { } std::string SymbolSet::parseNmOutputLine(std::string line) { - std::cout << "Read: " << std::endl; - std::cout << line << std::endl; - std::cout << "--------" << std::endl; std::string symbol = ""; if (line.find("FUNC|") != std::string::npos) { - std::cout << "Function:" << std::endl; symbol = line.substr(0, line.find('|')); - std::cout << symbol << std::endl; - } else { - std::cout << "Not a function" << std::endl; } return symbol; } @@ -64,7 +57,6 @@ void SymbolSet::parseNmOutput(std::ifstream& nm_out, const std::string& lib) { } void SymbolSet::generateSymbolFile(std::string filePath, std::string target) { - std::cout << __FUNCTION__ << "(): arguments: " << filePath << ", " << target << std::endl; std::string nm_output = "nm.out"; std::string nm_error = "nm.err"; std::string libFiles; diff --git a/tester/covoar/covoar.cc b/tester/covoar/covoar.cc index 868f40d..cbef875 100644 --- a/tester/covoar/covoar.cc +++ b/tester/covoar/covoar.cc @@ -367,12 +367,12 @@ int main( //Read symbol configuration file and load needed symbols if(symbolSetFile) { - cout << "Reading symbols sets configuration for symbol set file: " << symbolSetFile << endl; + fprintf(stderr,"Reading symbols sets configuration for symbol set file: %s\n", symbolSetFile); Symbols::SymbolSetReader ssr; std::vector<Symbols::SymbolSet> symbolSets = ssr.readSetFile(symbolSetFile); Symbols::SymbolSet& set = symbolSets[0]; - cout << "Generating symbol file for " << set.getName() << endl; + fprintf(stderr,"Generating symbol file for %s\n", set.getName().c_str()); set.generateSymbolFile(set.getName() + ".syms", target); SymbolsToAnalyze->load((set.getName() + ".syms").c_str()); } -- 1.9.1
From 01600e07070f40a21f1131a33119bbd76aeae1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Mi=C4=99sowicz?= <krzysztof.miesow...@gmail.com> Date: Wed, 27 Aug 2014 15:11:53 +0200 Subject: [PATCH 12/12] Exemplary symbolSets.config file added --- tester/rtems/testing/coverage/symbolSets.config | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tester/rtems/testing/coverage/symbolSets.config diff --git a/tester/rtems/testing/coverage/symbolSets.config b/tester/rtems/testing/coverage/symbolSets.config new file mode 100644 index 0000000..24e5040 --- /dev/null +++ b/tester/rtems/testing/coverage/symbolSets.config @@ -0,0 +1,11 @@ +symbolset: + name=score + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/score/libscore.a +symbolset: + name=filesystems + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/libdevfs.a + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/libdosfs.a + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/libimfs.a + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/librfs.a + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/libjffs2.a + lib=/home/krzysztof/development/rtems/src/b-pc386/i386-rtems4.11/c/pc386/cpukit/libfs/libdefaultfs.a \ No newline at end of file -- 1.9.1
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel