Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nedbat committed Sep 1, 2024
1 parent d86e46e commit b47957f
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
4 changes: 4 additions & 0 deletions coverage/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ def __init__(self, warn: TWarnFn, config: CoverageConfig, metacov: bool) -> None
warn("sys.monitoring isn't available, using default core", slug="no-sysmon")
core_name = None

if core_name == "sysmon" and config.branch and not env.PYBEHAVIOR.branch_taken:
warn("sys.monitoring can't yet measure branches well, using default core", slug="no-sysmon")
core_name = None

if not core_name:
# Once we're comfortable with sysmon as a default:
# if env.PYBEHAVIOR.pep669 and self.should_start_context is None:
Expand Down
2 changes: 1 addition & 1 deletion coverage/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class PYBEHAVIOR:
# Does sys.monitoring support BRANCH_TAKEN?
branch_taken = (
pep669 and
hasattr(sys.monitoring.events, "BRANCH_TAKEN") # type:ignore[attr-defined]
hasattr(sys.monitoring.events, "BRANCH_TAKEN") # type:ignore[attr-defined,unused-ignore]
)


Expand Down
46 changes: 26 additions & 20 deletions coverage/sysmon.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
if TYPE_CHECKING:
assert sys_monitoring is not None
# I want to say this but it's not allowed:
# MonitorReturn = Literal[sys.monitoring.DISABLE] | None
MonitorReturn = Any
MonitorReturn = Literal[sys.monitoring.DISABLE] | None
#MonitorReturn = Any


if LOG: # pragma: debugging
Expand All @@ -73,7 +73,10 @@ def _wrapped(*args: Any, **kwargs: Any) -> Any:
assert sys_monitoring is not None

short_stack = functools.partial(
short_stack, full=True, short_filenames=True, frame_ids=True,
short_stack,
full=True,
short_filenames=True,
frame_ids=True,
)
seen_threads: set[int] = set()

Expand Down Expand Up @@ -127,7 +130,9 @@ def _wrapped(self: Any, *args: Any) -> Any:
return ret
except Exception as exc:
log(f"!!{exc.__class__.__name__}: {exc}")
log("".join(traceback.format_exception(exc))) # pylint: disable=[no-value-for-parameter]
if 1:
# pylint: disable=no-value-for-parameter
log("".join(traceback.format_exception(exc)))
try:
assert sys_monitoring is not None
sys_monitoring.set_events(sys.monitoring.COVERAGE_ID, 0)
Expand Down Expand Up @@ -201,7 +206,6 @@ def __init__(self, tool_id: int) -> None:
# A list of code_objects, just to keep them alive so that id's are
# useful as identity.
self.code_objects: list[CodeType] = []
self.last_lines: dict[FrameType, int] = {}
# Map id(code_object) -> code_object
self.local_event_codes: dict[int, CodeType] = {}
self.sysmon_on = False
Expand Down Expand Up @@ -346,38 +350,38 @@ def sysmon_py_start(self, code: CodeType, instruction_offset: int) -> MonitorRet
with self.lock:
if self.sysmon_on:
assert sys_monitoring is not None
sys_monitoring.set_local_events(
self.myid,
code,
local_events = (
events.PY_RETURN
#
| events.PY_RESUME
# | events.PY_YIELD
| events.LINE
| events.BRANCH_TAKEN
| events.BRANCH_NOT_TAKEN
# | events.JUMP
)
if self.trace_arcs:
assert env.PYBEHAVIOR.branch_taken
local_events |= events.BRANCH_TAKEN | events.BRANCH_NOT_TAKEN
sys_monitoring.set_local_events(self.myid, code, local_events)
self.local_event_codes[id(code)] = code

if tracing_code and self.trace_arcs:
frame = self.callers_frame()
self.last_lines[frame] = -code.co_firstlineno
return None
else:
return sys.monitoring.DISABLE
return sys.monitoring.DISABLE

@panopticon("code", "@")
def sysmon_py_resume_arcs(
self, code: CodeType, instruction_offset: int,
self,
code: CodeType,
instruction_offset: int,
) -> MonitorReturn:
"""Handle sys.monitoring.events.PY_RESUME events for branch coverage."""
frame = self.callers_frame()
self.last_lines[frame] = frame.f_lineno

@panopticon("code", "@", None)
def sysmon_py_return_arcs(
self, code: CodeType, instruction_offset: int, retval: object,
self,
code: CodeType,
instruction_offset: int,
retval: object,
) -> MonitorReturn:
"""Handle sys.monitoring.events.PY_RETURN events for branch coverage."""
frame = self.callers_frame()
Expand All @@ -394,7 +398,10 @@ def sysmon_py_return_arcs(

@panopticon("code", "@", "exc")
def sysmon_py_unwind_arcs(
self, code: CodeType, instruction_offset: int, exception: BaseException,
self,
code: CodeType,
instruction_offset: int,
exception: BaseException,
) -> MonitorReturn:
"""Handle sys.monitoring.events.PY_UNWIND events for branch coverage."""
frame = self.callers_frame()
Expand All @@ -410,7 +417,6 @@ def sysmon_py_unwind_arcs(
# log(f"adding {arc=}")
cast(Set[TArc], code_info.file_data).add(arc)


@panopticon("code", "line")
def sysmon_line_lines(self, code: CodeType, line_number: int) -> MonitorReturn:
"""Handle sys.monitoring.events.LINE events for line coverage."""
Expand Down
8 changes: 7 additions & 1 deletion tests/test_concurrency.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,13 +554,19 @@ def test_multiprocessing_with_branching(self, start_method: str) -> None:
code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
total = sum(x*x if x%2 else x*x*x for x in range(upto))
expected_out = f"{nprocs} pids, total = {total}"
expect_warn = (
env.PYBEHAVIOR.pep669
and (not env.PYBEHAVIOR.branch_taken)
and testenv.SYS_MON
)
self.make_file("multi.py", code)
self.make_file("multi.rc", """\
[run]
concurrency = multiprocessing
branch = True
omit = */site-packages/*
""")
""" + ("disable_warnings = no-sysmon" if expect_warn else "")
)

out = self.run_command(f"coverage run --rcfile=multi.rc multi.py {start_method}")
assert out.rstrip() == expected_out
Expand Down

0 comments on commit b47957f

Please sign in to comment.