Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements incremental analysis experiment #577

Draft
wants to merge 95 commits into
base: vara-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 87 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
928308e
Small refactoring for fm provider
vulder Nov 23, 2021
3a70322
Adds project for FeaturePerfCS repo
vulder Nov 23, 2021
724d158
Cleans up compiler handling for lrzip
vulder Nov 23, 2021
aa39871
Adds initial draft of feature perf runner
vulder Nov 23, 2021
9ff98d2
Adds exception should a FM not be found
vulder Nov 23, 2021
7394108
Implements core report discovery
vulder Nov 24, 2021
7e87e2a
Small clean up
vulder Nov 24, 2021
2115e2b
Implements report for trace event format
vulder Nov 24, 2021
2b6c521
Merge branch 'f-FeaturePerfMeasure' into f-IncrementalExperiment
vulder Nov 30, 2021
c05774e
Initial draft of inc experiment
vulder Dec 1, 2021
5b24147
Initial draft of the incremental comparision experiment
vulder Dec 5, 2021
b027025
Implements initial commit look up
vulder Dec 5, 2021
a7651d6
Fixes inc experiment bb auto gen
vulder Dec 5, 2021
d2197df
Fix commit range calc
vulder Dec 5, 2021
3e9e42a
Implement commit calc
vulder Dec 5, 2021
ac418e1
Adds test scenarios for inc analysis experiment
vulder Dec 5, 2021
4be3557
Implements RevisionBinaryMap
vulder Dec 22, 2021
db39b5e
Ports binary handling and makes look ups compatible to new BB features
vulder Dec 22, 2021
d06fe88
Implements BC files caching for inc analysis experiment
vulder Dec 22, 2021
ebf4203
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Dec 22, 2021
0aeae5e
Fixes mypy type errors
vulder Dec 22, 2021
b1f55f3
Makes incremental analysis more flexible
vulder Jan 18, 2022
24a387f
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Jan 18, 2022
cf83d19
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Jan 21, 2022
c54b5ff
A bit of cleanup for types etc.
vulder Jan 21, 2022
54b5c21
Adds revision specific bc caching
vulder Jan 21, 2022
ac879cf
Small fixes in experiment
vulder Jan 21, 2022
aa9765d
Implements zip based report packing
vulder Jan 21, 2022
386dad9
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Feb 1, 2022
88f4b2d
Implements a paper config specific git filter
vulder Feb 3, 2022
878a3f0
Merge branch 'f-PCFilter' into f-IncrementalExperiment
vulder Feb 3, 2022
bc9d0f8
Adapt impl to new BB API
vulder Feb 3, 2022
c78ae96
Adapts docs to new source specifier
vulder Feb 3, 2022
3d79441
Clean up xz
vulder Feb 3, 2022
ec9d2b4
Merge branch 'vara-dev' into f-PCFilter
vulder Feb 3, 2022
1c47227
Move from filter to special git impl
vulder Feb 3, 2022
8d63f46
Fixes docs
vulder Feb 3, 2022
a43ab83
Revert "Implements a paper config specific git filter"
vulder Feb 3, 2022
0aa29fa
Merge branch 'f-PCFilter' into f-IncrementalExperiment
vulder Feb 3, 2022
cced5e9
Fixes missing import
vulder Feb 3, 2022
5ae553f
Port more projects
vulder Feb 3, 2022
15ea9e5
Port rest of the projects
vulder Feb 3, 2022
9bf04ae
Pull in new BB version
vulder Feb 3, 2022
8408fc9
Merge branch 'f-PCFilter' into f-IncrementalExperiment
vulder Feb 3, 2022
d87297b
Pull in new BB version 6.3
vulder Feb 3, 2022
040bcdf
Adapt action numbers
vulder Feb 3, 2022
50847cd
Merge branch 'f-UpdateBB' into f-PCFilter
vulder Feb 3, 2022
d808d9e
Merge branch 'f-PCFilter' into f-IncrementalExperiment
vulder Feb 3, 2022
a1bf81b
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Feb 4, 2022
e6326d9
port scenarios to new repo source
vulder Feb 5, 2022
01ed18a
remove submodule
vulder Feb 5, 2022
f30bdae
Adds project names to sources
vulder Feb 5, 2022
7877caa
trigger CI
vulder Feb 5, 2022
b0dc80c
Adds inital tablelayout to generated val table
vulder Feb 11, 2022
dc98e18
Fixes invers coloring
vulder Feb 11, 2022
179eb17
Adds draft impl for phasar-inc time report loading
vulder Feb 12, 2022
2793b69
Small analysis fixes
vulder Feb 12, 2022
f6a47a0
remove old filters
vulder Feb 12, 2022
670ef06
Port table to load actual timing data
vulder Feb 14, 2022
4df7d9f
Add own metrics table for inc paper
vulder Feb 14, 2022
5b8f069
Adds initial test version for delta-inc violin plot
vulder Feb 14, 2022
d84d129
Implements code only revision sampling
vulder Feb 16, 2022
799f436
Implements code only revision sampling
vulder Feb 16, 2022
ae77457
Merge branch 'f-SampleOnly' into f-IncrementalExperiment
vulder Feb 16, 2022
c124c97
Remove unused import
vulder Feb 16, 2022
44747d7
Merge branch 'f-SampleOnly' into f-IncrementalExperiment
vulder Feb 16, 2022
9f53183
Implements revisions selection based on a time range
vulder Feb 16, 2022
ecdfa9e
Implements revisions selection based on a time range
vulder Feb 16, 2022
1b52edd
Merge branch 'f-SampleOnly' into f-SelectDatetime
vulder Feb 16, 2022
c90afbb
Make test not dependent on time
vulder Feb 16, 2022
5fec03a
Merge branch 'f-SelectDatetime' into f-IncrementalExperiment
vulder Feb 17, 2022
0bc1f85
Aggregate reports into one value per project
vulder Feb 17, 2022
cf22775
Add total to result overview table
vulder Feb 19, 2022
75302cd
Implements violin plot to visualize helper analyses
vulder Feb 19, 2022
9936430
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Feb 28, 2022
7f7766f
Fixes mount specifier for older buildah versions
vulder Feb 28, 2022
602be45
Reworks helper analysis plot to show time deltas
vulder Mar 1, 2022
bf06eef
Remove y limit
vulder Mar 1, 2022
81fe37f
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Mar 1, 2022
5a4d06a
Adds multiplot
vulder Mar 2, 2022
586a226
Fixes timestamp based revision sampling
vulder Mar 2, 2022
c377cfe
Fixes timestamp based revision sampling
vulder Mar 2, 2022
e4a56da
Merge branch 'f-InitialFix' into f-IncrementalExperiment
vulder Mar 2, 2022
31d656d
Ignore blocked revisions by default
vulder Mar 2, 2022
785a01c
Merge branch 'f-IgnoreBlockedByDefault' into f-IncrementalExperiment
vulder Mar 2, 2022
1411aaa
Refactor zipping folder into own util class
vulder Mar 2, 2022
83a5e4b
Require new BB version
vulder Mar 2, 2022
977f567
Enable opt builds
vulder Mar 7, 2022
b6d34a5
Update varats/varats/plots/incremental_eval.py
vulder Mar 24, 2022
28b6679
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Apr 14, 2022
efe6cea
Fixes filename access
vulder Apr 21, 2022
51c5865
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Jul 12, 2022
3eaea16
Merge table to document utilitiy function
vulder Jul 12, 2022
882f56b
Migrate tables to new generator format
vulder Jul 12, 2022
a28b008
Merge branch 'vara-dev' into f-IncrementalExperiment
vulder Sep 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion tests/data/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class TestFileStatusExtension(unittest.TestCase):
"""Test basic FileStatusExtension functionality."""

def test_status_extension(self):
""""""
"""Tests if we convert a FSE to it's string representation."""
self.assertEqual(
FileStatusExtension.SUCCESS.get_status_extension(), "success"
)
Expand Down Expand Up @@ -62,6 +62,11 @@ def test_wrong_status_lookup(self):
class TestReportFilename(unittest.TestCase):
"""Test basic TestReportFilename functionality."""

correct_UUID: str
raw_filename: str
report_filename: ReportFilename
broken_report_filename: ReportFilename

@classmethod
def setUpClass(cls):
"""Setup file and CommitReport."""
Expand Down Expand Up @@ -151,6 +156,10 @@ def test_get_uuid(self):
class TestBaseReport(unittest.TestCase):
"""Test basic BaseReport functionality."""

success_filename_cr: str
success_filename: str
fail_filename: str

@classmethod
def setUpClass(cls):
"""Setup report file paths."""
Expand Down
235 changes: 235 additions & 0 deletions tests/report/test_tef_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
"""Test TEFReport."""

import json
import unittest
from pathlib import Path
from unittest import mock

from varats.report.tef_report import TEFReport, TraceEvent, TraceEventType

TRACE_EVENT_FORMAT_OUTPUT = """{
"traceEvents": [{
"name": "Base",
"cat": "Feature",
"ph": "B",
"ts": 1637675320727304236,
"pid": 91098,
"tid": 91098
}, {
"name": "Foo",
"cat": "Feature",
"ph": "B",
"ts": 1637675320727316656,
"pid": 91098,
"tid": 91098
}, {
"name": "Foo",
"cat": "Feature",
"ph": "E",
"ts": 1637675325727410375,
"pid": 91098,
"tid": 91098
}, {
"name": "Bar",
"cat": "Feature",
"ph": "B",
"ts": 1637675328727504858,
"pid": 91098,
"tid": 91098
}, {
"name": "Bar",
"cat": "Feature",
"ph": "E",
"ts": 1637675331727788401,
"pid": 91098,
"tid": 91098
}, {
"name": "Foo_2",
"cat": "Feature",
"ph": "B",
"ts": 1637675335727890982,
"pid": 91098,
"tid": 91098
}, {
"name": "Foo_2",
"cat": "Feature",
"ph": "E",
"ts": 1637675341728002649,
"pid": 91098,
"tid": 91098
}, {
"name": "Base",
"cat": "Feature",
"ph": "E",
"ts": 1637675341728008439,
"pid": 91098,
"tid": 91098
} ],
"displayTimeUnit": "ns",
"stackFrames": {}
}
"""


class TestTraceEventType(unittest.TestCase):
"""Test if we can correclty parse TraceEventTypes."""

def test_parse_duration_events(self) -> None:
"""Test if we correctly parse duration event types."""
self.assertEqual(
TraceEventType.parse_event_type("B"),
TraceEventType.DURATION_EVENT_BEGIN
)
self.assertEqual(
TraceEventType.parse_event_type("E"),
TraceEventType.DURATION_EVENT_END
)

def test_parse_async_events(self) -> None:
"""Test if we correctly parse async event types."""
self.assertEqual(
TraceEventType.parse_event_type("b"),
TraceEventType.ASYNC_EVENT_START
)
self.assertEqual(
TraceEventType.parse_event_type("n"),
TraceEventType.ASYNC_EVENT_INSTANT
)
self.assertEqual(
TraceEventType.parse_event_type("e"), TraceEventType.ASYNC_EVENT_END
)

def test_parse_flow_events(self) -> None:
"""Test if we correctly parse flow event types."""
self.assertEqual(
TraceEventType.parse_event_type("s"),
TraceEventType.FLOW_EVENT_START
)
self.assertEqual(
TraceEventType.parse_event_type("t"), TraceEventType.FLOW_EVENT_STEP
)
self.assertEqual(
TraceEventType.parse_event_type("f"), TraceEventType.FLOW_EVENT_END
)

def test_parse_other_events(self) -> None:
"""Test if we correctly parse other event types."""
self.assertEqual(
TraceEventType.parse_event_type("X"), TraceEventType.COMPLETE_EVENT
)
self.assertEqual(
TraceEventType.parse_event_type("i"), TraceEventType.INSTANT_EVENT
)
self.assertEqual(
TraceEventType.parse_event_type("C"), TraceEventType.COUNTER_EVENT
)
self.assertEqual(
TraceEventType.parse_event_type("P"), TraceEventType.SAMPLE_EVENT
)

def test_fail_at_wrong_event_string(self) -> None:
"""Test if we fail should an event type not match."""
self.assertRaises(LookupError, TraceEventType.parse_event_type, "42")
self.assertRaises(LookupError, TraceEventType.parse_event_type, "I")
self.assertRaises(LookupError, TraceEventType.parse_event_type, "D")
self.assertRaises(LookupError, TraceEventType.parse_event_type, "d")


SINGLE_TRACE_EVENT = """{
"name": "Base",
"cat": "Feature",
"ph": "E",
"ts": 1637675341728008439,
"pid": 91098,
"tid": 91099
}
"""


class TestTraceEvent(unittest.TestCase):
"""Test if we can correctly load trace events and parse values."""

trace_event: TraceEvent

@classmethod
def setUpClass(cls):
"""Load trace event."""
cls.trace_event = TraceEvent(json.loads(SINGLE_TRACE_EVENT))

def test_name_parsing(self):
"""Test if we can correctly parse event names."""
self.assertEqual(self.trace_event.name, "Base")
self.assertNotEqual(self.trace_event.name, "Foo")

def test_category_parsing(self):
"""Test if we can correctly parse event categories."""
self.assertEqual(self.trace_event.category, "Feature")
self.assertNotEqual(self.trace_event.name, "Foo")

def test_event_type_parsing(self):
"""Test if we can correctly parse event type."""
self.assertEqual(
self.trace_event.event_type, TraceEventType.DURATION_EVENT_END
)
self.assertIsInstance(self.trace_event.event_type, TraceEventType)
self.assertNotEqual(
self.trace_event.event_type, TraceEventType.DURATION_EVENT_BEGIN
)

def test_timestamp_parsing(self):
"""Test if we can correctly parse event timestamps."""
self.assertEqual(self.trace_event.timestamp, 1637675341728008439)
self.assertIsInstance(self.trace_event.timestamp, int)

self.assertNotEqual(self.trace_event.name, 1637675341728008438)
self.assertNotEqual(self.trace_event.name, 0)

def test_pid_parsing(self):
"""Test if we can correctly parse event pid."""
self.assertEqual(self.trace_event.pid, 91098)
self.assertIsInstance(self.trace_event.pid, int)

self.assertNotEqual(self.trace_event.name, 91099)
self.assertNotEqual(self.trace_event.name, 91097)
self.assertNotEqual(self.trace_event.name, 0)

def test_tid_parsing(self):
"""Test if we can correctly parse event tid."""
self.assertEqual(self.trace_event.tid, 91099)
self.assertIsInstance(self.trace_event.tid, int)

self.assertNotEqual(self.trace_event.name, 91100)
self.assertNotEqual(self.trace_event.name, 91098)
self.assertNotEqual(self.trace_event.name, 0)


class TestTEFReportParser(unittest.TestCase):
"""Tests if the trace-event-format report can be parsed correctly."""

report: TEFReport

@classmethod
def setUpClass(cls):
"""Load and prepare TEF report."""
with mock.patch(
'builtins.open',
new=mock.mock_open(read_data=TRACE_EVENT_FORMAT_OUTPUT)
):
cls.report = TEFReport(Path("fake_file_path"))

def test_parse_time_unit(self) -> None:
"""Test if the time unit field is correclty parsed."""
self.assertEqual(self.report.display_time_unit, "ns")
self.assertNotEqual(self.report.display_time_unit, "ms")

def test_parse_trace_events(self) -> None:
"""Test if we correctly parse the listed trace events."""
self.assertEqual(len(self.report.trace_events), 8)

self.assertEqual(self.report.trace_events[0].name, "Base")

def test_parse_stack_frames(self) -> None:
"""Test if we correctly parse stack frames."""
# Currently, not implemented so we should get an exception.
with self.assertRaises(NotImplementedError):
_ = self.report.stack_frames
30 changes: 30 additions & 0 deletions tests/tools/test_driver_casestudy.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,36 @@ def test_vara_cs_gen_sample_start_end_timestamp(self):
case_study.revisions
)

@run_in_test_environment()
def test_vara_cs_gen_sample_start_before_initial_commit(self):
"""Check if vara-cs gen select_sample with start timestamp before the
initial commit selects the right revisiosn."""
runner = CliRunner()
Path(vara_cfg()["paper_config"]["folder"].value + "/" +
"test_gen").mkdir()
vara_cfg()["paper_config"]["current_config"] = "test_gen"
result = runner.invoke(
driver_casestudy.main, [
'gen', '-p', 'brotli', 'select_sample', '--num-rev', '6',
'--start', '1991-01-01', '--end', '2013-10-20',
'UniformSamplingMethod'
]
)

self.assertEqual(0, result.exit_code, result.exception)
case_study_path = Path(
vara_cfg()["paper_config"]["folder"].value +
"/test_gen/brotli_0.case_study"
)
self.assertTrue(case_study_path.exists())

case_study = load_case_study_from_file(case_study_path)
self.assertEqual(len(case_study.revisions), 1)
self.assertTrue(
FullCommitHash('e0346c826249368f0f4a68a2b95f4ab5cf1e235b') in
case_study.revisions
)

@run_in_test_environment()
def test_vara_cs_gen_latest(self):
"""Test for vara-cs gen select_latest."""
Expand Down
3 changes: 2 additions & 1 deletion tests/utils/test_bb_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ def test_if_experiments_were_added(self):
"varats.experiments.discover_experiments",
"varats.experiments.vara.region_instrumentation",
"varats.experiments.vara.commit_annotation_report",
"varats.experiments.vara.blame_experiment"
"varats.experiments.vara.blame_experiment",
"varats.experiments.phasar.incremental_analysis"
]

loaded_plugins = bb_cfg()["plugins"]["experiments"].value
Expand Down
8 changes: 4 additions & 4 deletions tests/utils/test_git_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ def test_get_all_revisions_between_full(self):
self.assertSetEqual(
set(revs), {
FullCommitHash("5692e422da6af1e991f9182345d58df87866bc5e"),
FullCommitHash("2f9277ff2f2d0b4113b1ffd9753cc0f6973d354a"),
FullCommitHash("2a51a85aa86abb4c294c65fab57f3d9c69f10080"),
FullCommitHash("63be8a99401992075c23e99f7c84de1c653e39e2"),
FullCommitHash("2a51a85aa86abb4c294c65fab57f3d9c69f10080")
FullCommitHash("2f9277ff2f2d0b4113b1ffd9753cc0f6973d354a")
}
)

Expand All @@ -108,9 +108,9 @@ def test_get_all_revisions_between_short(self):
self.assertSetEqual(
set(revs), {
ShortCommitHash("5692e422da"),
ShortCommitHash("2f9277ff2f"),
ShortCommitHash("2a51a85aa8"),
ShortCommitHash("63be8a9940"),
ShortCommitHash("2a51a85aa8")
ShortCommitHash("2f9277ff2f")
}
)

Expand Down
2 changes: 1 addition & 1 deletion varats-core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
setup_requires=["pytest-runner", "setuptools_scm"],
tests_require=["pytest", "pytest-cov"],
install_requires=[
"benchbuild>=6.3.0",
"benchbuild>=6.3.1",
"plumbum>=1.6.6",
"PyGithub>=1.47",
"PyDriller>=2.0",
Expand Down
27 changes: 27 additions & 0 deletions varats-core/varats/experiment/experiment_util.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""Utility module for BenchBuild experiments."""

import os
import shutil
import random
import traceback
import typing as tp
from abc import abstractmethod
from pathlib import Path
import tempfile

from benchbuild import source
from benchbuild.experiment import Experiment
Expand Down Expand Up @@ -472,3 +474,28 @@ def experiment_filter(file_path: Path) -> bool:
return get_tagged_revisions(
project_cls, result_file_type, tag_blocked, experiment_filter
)


class ZippedReportFolder(tempfile.TemporaryDirectory):
"""
Context manager for creating a folder report, i.e., a report file which is
actually a folder containing multiple files and other folders.

Example usage: An experiment step can, with this context manager, simply
create a folder into which all kinds of data is dropped into. After the
completion of the step (leaving the context manager), all files dropped
into the folder will be compressed and stored as a single report.
"""

def __init__(self, result_report_path: Path) -> None:
super().__init__()
self.__result_report_name: Path = result_report_path.with_suffix('')

def __enter__(self) -> Path:
return Path(super().__enter__())

def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
shutil.make_archive(
str(self.__result_report_name), "zip", Path(self.name)
)
super().__exit__(exc_type, exc_value, exc_traceback)
Loading