Skip to content

Commit

Permalink
End of code region is not inside code region anymore. Fixes that some…
Browse files Browse the repository at this point in the history
… GAP Regions had vara_instrs. Improves confusion matrices.
  • Loading branch information
danjujan committed Aug 2, 2023
1 parent 7999b24 commit b89b05b
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 33 deletions.
52 changes: 44 additions & 8 deletions tests/data/test_llvm_coverage_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def setUp(self):

self.root = CodeRegion.from_list([0, 0, 100, 100, 5, 0, 0, 0], "main",
["test.txt"])
self.left = CodeRegion.from_list([0, 1, 49, 100, 5, 0, 0, 0], "main",
self.left = CodeRegion.from_list([0, 1, 50, 0, 5, 0, 0, 0], "main",
["test.txt"])
self.right = CodeRegion.from_list([50, 0, 100, 99, 5, 0, 0, 0], "main",
["test.txt"])
Expand Down Expand Up @@ -212,6 +212,34 @@ def test_insert_2(self):
root.insert(left_child)
self.assertIs(left.childs[0], left_child)

def test_insert_3(self):

root = CodeRegion.from_list([0, 0, 100, 100, 5, 0, 0, 0], "main",
["test.txt"])
left = CodeRegion.from_list([0, 1, 50, 100, 5, 0, 0, 0], "main",
["test.txt"])
right = CodeRegion.from_list([50, 0, 100, 100, 5, 0, 0, 0], "main",
["test.txt"])
root.insert(right)
with self.assertRaises(ValueError):
root.insert(left)

def test_overlap(self):

root = CodeRegion.from_list([0, 0, 100, 100, 5, 0, 0, 0], "main",
["test.txt"])
left = CodeRegion.from_list([0, 1, 50, 100, 5, 0, 0, 0], "main",
["test.txt"])
right = CodeRegion.from_list([50, 0, 100, 100, 5, 0, 0, 0], "main",
["test.txt"])

self.assertFalse(left.overlaps(root))
self.assertFalse(right.overlaps(root))
self.assertFalse(root.overlaps(left))
self.assertFalse(root.overlaps(right))
self.assertTrue(left.overlaps(right))
self.assertTrue(right.overlaps(left))

def test_find_region(self):
self.assertEqual(
self.root.find_code_region(line=0, column=0), self.root
Expand All @@ -226,11 +254,9 @@ def test_find_region(self):
self.root.find_code_region(line=50, column=0), self.right
)
self.assertEqual(
self.root.find_code_region(line=100, column=99), self.right
)
self.assertEqual(
self.root.find_code_region(line=100, column=100), self.root
self.root.find_code_region(line=100, column=99), self.root
)
self.assertEqual(self.root.find_code_region(line=100, column=100), None)
self.assertEqual(
self.root.find_code_region(line=10, column=0), self.left_left_2
)
Expand Down Expand Up @@ -303,9 +329,19 @@ def test_coverage_json_parsing(self):

report = CoverageReport.from_json(json_file, base_dir=tmp_dir)
code_region = report.tree["foo.cc"]
for region in code_region.iter_preorder():
print(region.count)
pass
self.assertEqual(code_region.total_count, 0)
self.assertEqual(code_region.childs[0].total_count, 20)
self.assertEqual(code_region.childs[0].childs[0].total_count, 20)
self.assertEqual(code_region.childs[0].childs[1].total_count, 2)
self.assertEqual(code_region.childs[1].total_count, 2)
self.assertEqual(code_region.childs[1].childs[0].total_count, 22)
self.assertEqual(code_region.childs[1].childs[1].total_count, 20)
self.assertEqual(code_region.childs[1].childs[2].total_count, 20)
self.assertEqual(code_region.childs[1].childs[3].total_count, 20)
self.assertEqual(
code_region.childs[1].childs[3].childs[0].total_count, 20
)
self.assertEqual(code_region.childs[2].total_count, 1)

@run_in_test_environment(
UnitTestFixtures.PAPER_CONFIGS, UnitTestFixtures.RESULT_FILES
Expand Down
12 changes: 6 additions & 6 deletions tests/plots/test_llvm_coverage_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,18 +550,18 @@ def test_confusion_matrices(self):
print(result)
enc = result["enc"]
self.assertEqual(enc.TP, 3)
self.assertEqual(enc.TN, 38)
self.assertEqual(enc.TN, 39)
self.assertEqual(enc.FP, 0)
self.assertEqual(enc.FN, 9)
self.assertEqual(enc.FN, 8)

compress = result["compress"]
self.assertEqual(compress.TP, 2)
self.assertEqual(compress.TN, 39)
self.assertEqual(compress.TN, 40)
self.assertEqual(compress.FP, 0)
self.assertEqual(compress.FN, 9)
self.assertEqual(compress.FN, 8)

all = result["__all__"]
self.assertEqual(all.TP, 4)
self.assertEqual(all.TN, 35)
self.assertEqual(all.TN, 36)
self.assertEqual(all.FP, 0)
self.assertEqual(all.FN, 11)
self.assertEqual(all.FN, 10)
47 changes: 36 additions & 11 deletions varats/varats/data/reports/llvm_coverage_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def expr_to_str(expression: Expression) -> str:


@dataclass
class CodeRegion: # pylint: disable=too-many-instance-attributes
class CodeRegion: # pylint: disable=too-many-instance-attributes, too-many-public-methods
"""Code region tree."""
start: RegionStart
end: RegionEnd
Expand Down Expand Up @@ -312,6 +312,23 @@ def is_subregion(self, other: CodeRegion) -> bool:

return start_ok and end_ok and not (start_equal and end_equal)

def overlaps(self, other: CodeRegion) -> bool:
"""
Tests if regions overlap.
They overlaps if they are not subregions, but one location is inside of
the other.
"""

if self.is_subregion(other) or other.is_subregion(self):
return False
if self.is_location_inside(
other.start.line, other.start.column
) != other.is_location_inside(self.start.line, self.start.column):
return True

return False

def add_instantiation(self, region: CodeRegion) -> None:
"""If a code region already exists in a tree."""
if region != self:
Expand Down Expand Up @@ -351,6 +368,10 @@ def insert(self, region: CodeRegion) -> None:
child.parent = region
node.childs.remove(child)

if any(child.overlaps(region) for child in node.childs):
raise ValueError(
"The given region overlaps with another region!"
)
node.childs.append(region)
node.childs.sort()
region.parent = node
Expand All @@ -363,6 +384,13 @@ def combine_features(self, region: CodeRegion) -> None:
raise AssertionError("CodeRegions are not identical")
x.presence_conditions.extend(y.presence_conditions)

def get_code_region(self, element: CodeRegion) -> tp.Optional[CodeRegion]:
"""Returns the code region if it exists already."""
for child in self.iter_breadth_first():
if child == element:
return child
return None

def find_code_region(self, line: int,
column: int) -> tp.Optional[CodeRegion]:
"""
Expand All @@ -386,13 +414,13 @@ def is_location_inside(self, line: int, column: int) -> bool:
# Location could be inside. Check cases.
if self.start.line == line == self.end.line:
# Location in same line
return self.start.column <= column <= self.end.column
return self.start.column <= column < self.end.column
if self.start.line == line:
# Location in start line
return self.start.column <= column
if self.end.line == line:
# Location in end line
return column <= self.end.column
return column < self.end.column
# Location neither in start line not in end line
return self.start.line < line < self.end.line
return False
Expand All @@ -405,9 +433,8 @@ def annotate_covered(self, configuration: Configuration) -> None:
"""
kind = PresenceKind.BECOMES_ACTIVE
for region in self.iter_breadth_first():
if region.kind == CodeRegionKind.GAP and len(
region.vara_instrs
) == 0:
if region.kind == CodeRegionKind.GAP:
assert len(region.vara_instrs) == 0
continue
if region.is_covered():
region.presence_conditions[kind].append(
Expand Down Expand Up @@ -497,13 +524,11 @@ def add(self, region: CodeRegion) -> None:
)
return
root_region = self[filename]
found_region = root_region.find_code_region(
region.start.line, region.start.column
)
if found_region is not None and found_region == region:
if (found_region := root_region.get_code_region(region)) is not None:
# Region exists already
found_region.add_instantiation(region)
if not region in root_region:
else:
# Region does not exist
root_region.insert(region)

def sorted(self) -> FilenameRegionMapping:
Expand Down
8 changes: 4 additions & 4 deletions varats/varats/plots/llvm_coverage_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,13 @@ def _plot_confusion_matrix(reports: CoverageReports, outdir: Path) -> None:
with outfile.open("w") as output:
output.write(f"{matrix}\n")
tps = [str(x) for x in matrix.getTPs()]
output.write(f"True Positives:\n{chr(10).join(tps)}\n")
output.write(f"True Positives:\n{chr(10).join(sorted(tps))}\n")
tns = [str(x) for x in matrix.getTNs()]
output.write(f"True Negatives:\n{chr(10).join(tns)}\n")
output.write(f"True Negatives:\n{chr(10).join(sorted(tns))}\n")
fps = [str(x) for x in matrix.getFPs()]
output.write(f"False Positives:\n{chr(10).join(fps)}\n")
output.write(f"False Positives:\n{chr(10).join(sorted(fps))}\n")
fns = [str(x) for x in matrix.getFNs()]
output.write(f"False Negatives:\n{chr(10).join(fns)}\n")
output.write(f"False Negatives:\n{chr(10).join(sorted(fns))}\n")


class CoveragePlotGenerator(
Expand Down
8 changes: 4 additions & 4 deletions varats/varats/projects/c_projects/xz.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@
from benchbuild.source import HTTPMultiple
from benchbuild.utils.cmd import autoreconf, make
from benchbuild.utils.revision_ranges import (
block_revisions,
GoodBadSubgraph,
RevisionRange,
block_revisions,
)
from benchbuild.utils.settings import get_number_of_jobs
from plumbum import local

from varats.containers.containers import get_base_image, ImageBase
from varats.containers.containers import ImageBase, get_base_image
from varats.experiment.workload_util import RSBinary, WorkloadCategory
from varats.paper.paper_config import PaperConfigSpecificGit
from varats.project.project_domain import ProjectDomains
from varats.project.project_util import (
BinaryType,
ProjectBinaryWrapper,
get_local_project_git_path,
BinaryType,
verify_binaries,
)
from varats.project.sources import FeatureSource
from varats.project.varats_project import VProject
from varats.utils.git_util import (
RevisionBinaryMap,
ShortCommitHash,
get_all_revisions_between,
RevisionBinaryMap,
)
from varats.utils.settings import bb_cfg

Expand Down

0 comments on commit b89b05b

Please sign in to comment.