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

Generate Feature-Blame-Report #784

Open
wants to merge 30 commits into
base: vara-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9722976
implement FeatureBlameReportExperiment
Apr 11, 2023
5d415a1
add test_repo to test projects
Apr 11, 2023
1405e8c
some nmae/type fixes
Apr 12, 2023
bb75269
correct binary?
Apr 12, 2023
44a4669
added print feature
Apr 13, 2023
fd99f6c
change config
Apr 13, 2023
11bf7ba
create bc with clang
Apr 13, 2023
5fe3a66
print out FBR
Apr 13, 2023
2603afc
remove unnecessary code
Apr 14, 2023
a1a9f4c
minor cleanup
Apr 14, 2023
edc3c4b
added new file
Apr 14, 2023
071b7c3
fixes for pre-commit hook
Apr 17, 2023
c52af3e
review changes
Apr 17, 2023
0deac4e
fixes by pre-commit
Apr 18, 2023
45f881f
Merge branch 'vara-dev' of github.com:se-sic/VaRA-Tool-Suite into f-G…
Apr 18, 2023
b3cad79
adapt code to work after pull from vara-dev
Apr 18, 2023
8a6f71e
adapted python fbr to new yaml fbr
May 22, 2023
2c56155
separated feature blame report
Jun 25, 2023
f3bf72b
Merge branch 'vara-dev' of github.com:se-sic/VaRA-Tool-Suite into f-G…
Jul 7, 2023
5e221e1
added detection of feature model
Jul 10, 2023
dafb1ba
refactoring
Sep 7, 2023
c5ee49a
Merge branch 'vara-dev' of github.com:se-sic/VaRA-Tool-Suite into f-G…
Sep 7, 2023
6c7e685
changes for checks
Sep 11, 2023
173d0c3
Merge branch 'vara-dev' of github.com:se-sic/VaRA-Tool-Suite into f-G…
Sep 11, 2023
c0abdde
added missing FeatureModelProvider to dataflow report
Sep 11, 2023
d542167
adapt test_bb_config for merge of experiments
Sep 11, 2023
519d96b
changes to review
Sep 14, 2023
dc5db5d
remove unused import
Sep 20, 2023
42de982
adapt to changes in structural cfi collection
Sep 25, 2023
5848c18
fix mistake in return type
Sep 25, 2023
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ tmp/
.tox/
docs/source/.varats.yaml
docs/**/*.inc
pre-commit-env
224 changes: 224 additions & 0 deletions varats/varats/data/reports/feature_blame_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
"""Module for StructuralFeatureBlameReport and DataflowFeatureBlameReport."""

import re
import typing as tp
from pathlib import Path

import yaml

from varats.base.version_header import VersionHeader
from varats.data.reports.blame_report import BlameReportMetaData
from varats.data.reports.feature_analysis_report import (
FeatureAnalysisReportMetaData,
)
from varats.report.report import BaseReport
from varats.utils.git_util import CommitRepoPair


class StructuralCommitFeatureInteraction():
"""A StructuralCommitFeatureInteraction detailing the specific commit-hash
and repo and feature and the number of instructions this structural cfi
occurs in."""

def __init__(
self, num_instructions: int, feature: str, commit: CommitRepoPair
) -> None:
self.__num_instructions = num_instructions
self.__feature = feature
self.__commit = commit

@staticmethod
def create_commit_feature_interaction(
raw_inst_entry: tp.Dict[str, tp.Any]
) -> 'StructuralCommitFeatureInteraction':
"""Creates a `StructuralCommitFeatureInteraction` entry from the
corresponding yaml document section."""
num_instructions = int(raw_inst_entry['num-instructions'])
feature: str = str(raw_inst_entry['feature'])
commit: CommitRepoPair = CommitRepoPair(
(raw_inst_entry['commit-repo-pair'])['commit'],
(raw_inst_entry['commit-repo-pair'])['repository']
)
return StructuralCommitFeatureInteraction(
num_instructions, feature, commit
)

def print(self) -> None:
"""'CommitFeatureInteraction' prints itself."""
print(" -COMMIT FEATURE INTERACTION")
print(" -NUM OF INSTRUCTIONS: " + str(self.__num_instructions))
print(" -FEATURE: " + self.__feature)
print(" -HASH: " + self.__commit.commit_hash.__str__())
print(" -REPO: " + self.__commit.repository_name)

@property
def num_instructions(self) -> int:
"""number of instructions the specified cfi occurs in."""
return self.__num_instructions

@property
def feature(self) -> str:
"""The feature of this cfi."""
return self.__feature

@property
def commit(self) -> CommitRepoPair:
"""commit of this cfi."""
return self.__commit

def is_terminator(self) -> bool:
br_regex = re.compile(r'(br( i1 | label ))|(switch i\d{1,} )')
return br_regex.search(self.__num_instructions) is not None


class StructuralFeatureBlameReportMetaData(FeatureAnalysisReportMetaData):
pass


class StructuralFeatureBlameReport(
BaseReport, shorthand="SFBR", file_type="yaml"
):
"""Data class that gives access to a loaded structural feature blame
report."""

def __init__(self, path: Path) -> None:
super().__init__(path)

with open(path, 'r') as stream:
documents = yaml.load_all(stream, Loader=yaml.CLoader)
version_header = VersionHeader(next(documents))
version_header.raise_if_not_type("StructuralFeatureBlameReport")
version_header.raise_if_version_is_less_than(1)

self.__meta_data = StructuralFeatureBlameReportMetaData \
.create_feature_analysis_report_meta_data(next(documents))

self.__commit_feature_interactions: tp.List[
StructuralCommitFeatureInteraction] = []
raw_feature_blame_report = next(documents)
for cfi in raw_feature_blame_report[
'structural-commit-feature-interactions']:
new_cfi = (
StructuralCommitFeatureInteraction.
create_commit_feature_interaction(cfi)
)
self.__commit_feature_interactions.append(new_cfi)

def print(self) -> None:
"""'FeatureBlameReport' prints itself."""
print("STRUCTURAL FEATURE BLAME REPORT")
for cfi in self.__commit_feature_interactions:
cfi.print()

@property
def meta_data(self) -> StructuralFeatureBlameReportMetaData:
"""Access the meta data that was gathered with the
``StructuralFeatureBlameReport``."""
return self.__meta_data

@property
def commit_feature_interactions(
self
) -> tp.ValuesView[StructuralCommitFeatureInteraction]:
"""Iterate over all cfis."""
return self.__commit_feature_interactions


##### DATAFLOW #####


class DataflowCommitFeatureInteraction():
"""A DataflowCommitFeatureInteraction detailing the specific commit-hash and
repo and feature this dataflow-based cfi occurs in."""

def __init__(self, feature: str, commits: tp.List[CommitRepoPair]) -> None:
self.__feature = feature
self.__commits = commits

@staticmethod
def create_commit_feature_interaction(
raw_inst_entry: tp.Dict[str, tp.Any]
) -> 'DataflowCommitFeatureInteraction':
"""Creates a `DataflowCommitFeatureInteraction` entry from the
corresponding yaml document section."""
feature: str = str(raw_inst_entry['feature'])
crps: tp.List[CommitRepoPair] = []
for crp in raw_inst_entry['commit-repo-pairs']:
crps.append(CommitRepoPair(crp['commit'], crp['repository']))
return DataflowCommitFeatureInteraction(feature, crps)

def print(self) -> None:
"""'CommitFeatureInteraction' prints itself."""
print(" -COMMIT FEATURE INTERACTION")
print(" -FEATURE: " + self.__feature)
print(" -COMMITS: ")
for commit in self.__commits:
print(" -COMMIT: " + commit.commit_hash)
print(" -REPO: " + commit.repository_name)

@property
def feature(self) -> str:
"""The feature of this cfi."""
return self.__feature

@property
def commit(self) -> tp.List[CommitRepoPair]:
"""commit of this cfi."""
return self.__commits

def is_terminator(self) -> bool:
br_regex = re.compile(r'(br( i1 | label ))|(switch i\d{1,} )')
return br_regex.search(self.__commits) is not None


class DataflowFeatureBlameReportMetaData(BlameReportMetaData):
pass


class DataflowFeatureBlameReport(
BaseReport, shorthand="DFBR", file_type="yaml"
):
"""Data class that gives access to a loaded dataflow feature blame
report."""

def __init__(self, path: Path) -> None:
super().__init__(path)

with open(path, 'r') as stream:
documents = yaml.load_all(stream, Loader=yaml.CLoader)
version_header = VersionHeader(next(documents))
version_header.raise_if_not_type("DataflowFeatureBlameReport")
version_header.raise_if_version_is_less_than(1)

self.__meta_data = DataflowFeatureBlameReportMetaData \
.create_blame_report_meta_data(next(documents))

self.__commit_feature_interactions: tp.List[
DataflowCommitFeatureInteraction] = []
raw_feature_blame_report = next(documents)
for cfi in raw_feature_blame_report[
'dataflow-commit-feature-interactions']:
new_cfi = (
DataflowCommitFeatureInteraction.
create_commit_feature_interaction(cfi)
)
self.__commit_feature_interactions.append(new_cfi)

def print(self) -> None:
"""'DataflowFeatureBlameReport' prints itself."""
print("DATAFLOW FEATURE BLAME REPORT")
for cfi in self.__commit_feature_interactions:
cfi.print()

@property
def meta_data(self) -> DataflowFeatureBlameReportMetaData:
"""Access the meta data that was gathered with the
``DataflowFeatureBlameReport``."""
return self.__meta_data

@property
def commit_feature_interactions(
self
) -> tp.ValuesView[DataflowCommitFeatureInteraction]:
"""Iterate over all cfis."""
return self.__commit_feature_interactions
73 changes: 73 additions & 0 deletions varats/varats/experiments/vara/feature_blame_experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Implements the base feature blame experiment, making it easier to create
sisteu56 marked this conversation as resolved.
Show resolved Hide resolved
different feature-blame experiments that have a similar experiment setup."""

import typing as tp

from benchbuild import Project
from benchbuild.extensions import compiler, run, time
from benchbuild.utils import actions

from varats.experiment.experiment_util import (
VersionExperiment,
get_default_compile_error_wrapped,
PEErrorHandler,
)
from varats.experiment.wllvm import (
RunWLLVM,
BCFileExtensions,
get_bc_cache_actions,
)
from varats.report.report import BaseReport


def setup_basic_feature_blame_experiment(
experiment: VersionExperiment, project: Project,
report_type: tp.Type[BaseReport]
) -> None:
"""
Setup the project for a feature blame experiment.

- run time extensions
- compile time extensions
- prepare compiler
- configure C/CXX flags
"""
# Add the required runtime extensions to the project(s).
project.runtime_extension = run.RuntimeExtension(project, experiment) \
<< time.RunWithTime()

# Add the required compiler extensions to the project(s).
project.compiler_extension = compiler.RunCompiler(project, experiment) \
<< RunWLLVM() \
<< run.WithTimeout()

# Add own error handler to compile step.
project.compile = get_default_compile_error_wrapped(
experiment.get_handle(), project, report_type
)

# This c-flag is provided by VaRA and it suggests to use the git-blame
# annotation.
project.cflags += ["-fvara-GB", "-fvara-feature"]


def generate_basic_feature_blame_experiment_actions(
project: Project,
bc_file_extensions: tp.Optional[tp.List[BCFileExtensions]] = None,
extraction_error_handler: tp.Optional[PEErrorHandler] = None
) -> tp.List[actions.Step]:
"""
Generate the basic actions for a feature blame experiment.

- handle caching of BC files
- compile project, if needed

Args:
project: reference to the BB project
bc_file_extensions: list of bitcode file extensions (e.g. opt, no opt)
extraction_error_handler: handler to manage errors during the
extraction process
"""
return get_bc_cache_actions(
project, bc_file_extensions, extraction_error_handler
)
Loading