Skip to content

Commit

Permalink
feat: Add ability to mask FPEs from code comment (acts-project#2277)
Browse files Browse the repository at this point in the history
Syntax is

```cpp
float v = 1.0 / 0.0; // MARK: fpeMask(FLTDIV, 1)
```

where you can specify the FPE type, and the maximum number per event that is tolerated. You can add multiple `fpeMask()` expressions per line.

NOTE: This will likely only work in case of running from the build directory, not from an installed one.
  • Loading branch information
paulgessinger committed Jul 24, 2023
1 parent 71cec00 commit 4798aec
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 4 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,14 @@ jobs:
- name: Check
run: >
CI/check_spelling
fpe_masks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Install dependencies
run: >
pip install -r CI/requirements_fpe_masks.txt
- name: Check
run: >
CI/check_fpe_masks.py --token ${{ secrets.GITHUB_TOKEN }}
94 changes: 94 additions & 0 deletions CI/check_fpe_masks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
from pathlib import Path
import os
import re
import sys

import asyncio
import aiohttp
import gidgethub
from gidgethub.aiohttp import GitHubAPI
import typer
from rich import print
from rich.rule import Rule


def main(
token: str = typer.Option(..., envvar="GITHUB_TOKEN"),
repo: str = typer.Option(..., envvar="GITHUB_REPOSITORY"),
):
asyncio.run(check(token, repo))


async def check(token: str, repo: str):
ok = True

async with aiohttp.ClientSession() as session:
gh = GitHubAPI(session=session, requester="acts-project", oauth_token=token)
srcdir = Path(__file__).parent.parent
for root, _, files in os.walk(srcdir):
root = Path(root)
for f in files:
if (
not f.endswith(".hpp")
and not f.endswith(".cpp")
and not f.endswith(".ipp")
):
continue
f = root / f
rel = f.relative_to(srcdir)
first = True
with f.open("r") as fh:
for i, line in enumerate(fh, start=1):
if m := re.match(r".*\/\/ ?MARK: ?(fpeMask.*)$", line):
if first:
print(Rule(str(rel)))
first = False
exp = m.group(1)
for m in re.findall(
r"fpeMask\((\w+), ?(\d+) ?, ?issue: ?(\d+)\)", exp
):
fpeType, count, number = m

loc = f"{rel}:{i}"
this_ok = True
issue_info = number
try:
issue = await gh.getitem(
f"repos/{repo}/issues/{number}"
)
issue_info = issue["html_url"]
except gidgethub.BadRequest as e:
print(
f":red_circle: [bold]FPE mask at {loc} has invalid issue number {number}[/bold]"
)
this_ok = False
continue

if issue["state"] != "open":
print(
f":red_circle: [bold]FPE mask at {loc} has issue {number} but is not open[/bold]"
)
this_ok = False
if not "fpe" in issue["title"].lower():
print(
f":red_circle: [bold]FPE mask at {loc} has issue {number} but does not contain 'FPE' / 'fpe' in the title[/bold]"
)
this_ok = False
if not "fpe" in [l["name"] for l in issue["labels"]]:
print(
f":red_circle: [bold]FPE mask at {loc} has issue {number} but does not have the 'fpe' label[/bold]"
)
this_ok = False

if this_ok:
print(
f":green_circle: [bold]FPE mask at {loc}: {fpeType} <= {count}[/bold]"
)

ok = ok and this_ok

raise typer.Exit(code=0 if ok else 1)


typer.run(main)
4 changes: 4 additions & 0 deletions CI/requirements_fpe_masks.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gidgethub
typer
rich
aiohttp
54 changes: 54 additions & 0 deletions CI/requirements_fpe_masks.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile CI/requirements_fpe_masks.in
#
aiohttp==3.8.4
# via -r CI/requirements_fpe_masks.in
aiosignal==1.3.1
# via aiohttp
async-timeout==4.0.2
# via aiohttp
attrs==23.1.0
# via aiohttp
cffi==1.15.1
# via cryptography
charset-normalizer==3.1.0
# via aiohttp
click==8.1.4
# via typer
cryptography==41.0.1
# via pyjwt
frozenlist==1.3.3
# via
# aiohttp
# aiosignal
gidgethub==5.3.0
# via -r CI/requirements_fpe_masks.in
idna==3.4
# via yarl
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
multidict==6.0.4
# via
# aiohttp
# yarl
pycparser==2.21
# via cffi
pygments==2.15.1
# via rich
pyjwt[crypto]==2.7.0
# via gidgethub
rich==13.4.2
# via -r CI/requirements_fpe_masks.in
typer==0.9.0
# via -r CI/requirements_fpe_masks.in
typing-extensions==4.7.1
# via typer
uritemplate==4.1.1
# via gidgethub
yarl==1.9.2
# via aiohttp
3 changes: 2 additions & 1 deletion Examples/Io/Root/src/RootTrajectorySummaryWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,8 @@ ActsExamples::ProcessCode ActsExamples::RootTrajectorySummaryWriter::writeT(

if (hasFittedCov) {
for (unsigned int i = 0; i < Acts::eBoundSize; ++i) {
pull[i] = res[i] / error[i];
pull[i] =
res[i] / error[i]; // MARK: fpeMask(FLTINV, 1, issue: 2284)
}
}
}
Expand Down
63 changes: 62 additions & 1 deletion Examples/Python/python/acts/examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from typing import Optional, Protocol, Union, List, Dict
import os
import re

from acts.ActsPythonBindings._examples import *
from acts import ActsPythonBindings
Expand Down Expand Up @@ -343,7 +344,11 @@ def customLogLevel(


class Sequencer(ActsPythonBindings._examples._Sequencer):

_autoFpeMasks: Optional[List["FpeMask"]] = None

def __init__(self, *args, **kwargs):

if "fpeMasks" in kwargs:
m = kwargs["fpeMasks"]
if isinstance(m, list) and len(m) > 0 and isinstance(m[0], tuple):
Expand All @@ -352,7 +357,23 @@ def __init__(self, *args, **kwargs):
t = _fpe_types_to_enum[fpe] if isinstance(fpe, str) else fpe
n.append(self.FpeMask(loc, t, count))
kwargs["fpeMasks"] = n
super().__init__(*args, **kwargs)

kwargs["fpeMasks"] = kwargs.get("fpeMasks", []) + self._getAutoFpeMasks()

cfg = self.Config()
if len(args) == 1 and isinstance(args[0], self.Config):
cfg = args[0]
args = args[1:]
if "config" in kwargs:
cfg = kwargs.pop("config")

for k, v in kwargs.items():
print("Set", k, v)
if not hasattr(cfg, k):
raise ValueError(f"Sequencer.Config does not have field {k}")
setattr(cfg, k, v)

super().__init__(cfg)

class FpeMask(ActsPythonBindings._examples._Sequencer._FpeMask):
@classmethod
Expand Down Expand Up @@ -396,3 +417,43 @@ def fromDict(cls, d: Dict[str, Dict[str, int]]) -> List["FpeMask"]:
for fpe, count in types.items():
out.append(cls(loc, cls._fpe_types_to_enum[fpe], count))
return out

@classmethod
def _getAutoFpeMasks(cls) -> List[FpeMask]:
if cls._autoFpeMasks is not None:
return cls._autoFpeMasks

srcdir = Path(cls._sourceLocation).parent.parent.parent.parent

cls._autoFpeMasks = []

for root, _, files in os.walk(srcdir):
root = Path(root)
for f in files:
if (
not f.endswith(".hpp")
and not f.endswith(".cpp")
and not f.endswith(".ipp")
):
continue
f = root / f
# print(f)
with f.open("r") as fh:
for i, line in enumerate(fh, start=1):
if m := re.match(r".*\/\/ ?MARK: ?(fpeMask.*)$", line):
exp = m.group(1)
for m in re.findall(
r"fpeMask\((\w+), ?(\d+) ?, ?issue: ?(\d+)\)", exp
):
fpeType, count, _ = m
count = int(count)
rel = f.relative_to(srcdir)
cls._autoFpeMasks.append(
cls.FpeMask(
f"{rel}:{i}",
cls.FpeMask._fpe_types_to_enum[fpeType],
count,
)
)

return cls._autoFpeMasks
5 changes: 4 additions & 1 deletion Examples/Python/src/ModuleEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ PYBIND11_MODULE(ActsPythonBindings, m) {
.def("addWriter", &Sequencer::addWriter)
.def("addWhiteboardAlias", &Sequencer::addWhiteboardAlias)
.def_property_readonly("config", &Sequencer::config)
.def_property_readonly("fpeResult", &Sequencer::fpeResult);
.def_property_readonly("fpeResult", &Sequencer::fpeResult)
.def_property_readonly_static(
"_sourceLocation",
[](py::object /*self*/) { return std::string{__FILE__}; });

auto c = py::class_<Config>(sequencer, "Config").def(py::init<>());

Expand Down

0 comments on commit 4798aec

Please sign in to comment.