Skip to content

Commit

Permalink
Work-around for #740, plus some code cleanup (#743)
Browse files Browse the repository at this point in the history
* Factored out a dataclass and some repetitive functionality.

* Added work-around for #740. More code cleanup.
  • Loading branch information
emeryberger authored Dec 17, 2023
1 parent 9512391 commit fca8de3
Showing 1 changed file with 42 additions and 50 deletions.
92 changes: 42 additions & 50 deletions scalene/scalene_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
"""

# Import cysignals early so it doesn't disrupt Scalene's use of signals; this allows Scalene to profile Sage.
# See https://github.com/plasma-umass/scalene/issues/740.
try:
import cysignals
except ModuleNotFoundError:
pass

import argparse
import atexit
import builtins
Expand Down Expand Up @@ -46,6 +53,7 @@
from scalene.redirect_python import redirect_python

from collections import defaultdict
from dataclasses import dataclass
from importlib.abc import SourceLoader
from importlib.machinery import ModuleSpec
from types import CodeType, FrameType
Expand Down Expand Up @@ -100,6 +108,13 @@ def nada(*args: Any) -> None:
MINIMUM_PYTHON_VERSION_MAJOR = 3
MINIMUM_PYTHON_VERSION_MINOR = 8

@dataclass
class time_info:
virtual : float
wallclock : float
sys : float
user : float


def require_python(version: Tuple[int, int]) -> None:
assert (
Expand Down Expand Up @@ -203,10 +218,7 @@ def get_original_lock() -> threading.Lock:
return Scalene.__original_lock()

# when did we last receive a signal?
__last_signal_time_virtual: float = 0
__last_signal_time_wallclock: float = 0
__last_signal_time_sys: float = 0
__last_signal_time_user: float = 0
__last_signal_time = time_info(0.0, 0.0, 0.0, 0.0)

# path for the program being profiled
__program_path = Filename("")
Expand Down Expand Up @@ -661,24 +673,12 @@ def __init__(
Scalene.__pid = 0
cmdline = ""
# Pass along commands from the invoking command line.
cmdline += f" --cpu-sampling-rate={arguments.cpu_sampling_rate}"
if arguments.use_virtual_time:
cmdline += " --use-virtual-time"
if "off" in arguments and arguments.off:
cmdline += " --off"
if arguments.cpu:
cmdline += " --cpu"
if arguments.gpu:
cmdline += " --gpu"
if arguments.memory:
cmdline += " --memory"
if arguments.cli:
cmdline += " --cli"
if arguments.web:
cmdline += " --web"
if arguments.no_browser:
cmdline += " --no-browser"

for arg in ["use_virtual_time", "cpu_sampling_rate", "cpu", "gpu", "memory",
"cli", "web", "no_browser", "reduced_profile"]:
if getattr(arguments, arg):
cmdline += f' --{arg.replace("_", "-")}'
# Build the commands to pass along other arguments
environ = ScalenePreload.get_preload_environ(arguments)
if sys.platform == "win32":
Expand Down Expand Up @@ -730,14 +730,14 @@ def cpu_signal_handler(
now_virtual = time.process_time()
now_wallclock = time.perf_counter()
if (
Scalene.__last_signal_time_virtual == 0
or Scalene.__last_signal_time_wallclock == 0
Scalene.__last_signal_time.virtual == 0
or Scalene.__last_signal_time.wallclock == 0
):
# Initialization: store values and update on the next pass.
Scalene.__last_signal_time_virtual = now_virtual
Scalene.__last_signal_time_wallclock = now_wallclock
Scalene.__last_signal_time_sys = now_sys
Scalene.__last_signal_time_user = now_user
Scalene.__last_signal_time.virtual = now_virtual
Scalene.__last_signal_time.wallclock = now_wallclock
Scalene.__last_signal_time.sys = now_sys
Scalene.__last_signal_time.user = now_user
if sys.platform != "win32":
Scalene.__orig_setitimer(
Scalene.__signals.cpu_timer_signal,
Expand All @@ -757,18 +757,18 @@ def cpu_signal_handler(
now_user,
gpu_load,
gpu_mem_used,
Scalene.__last_signal_time_virtual,
Scalene.__last_signal_time_wallclock,
Scalene.__last_signal_time_sys,
Scalene.__last_signal_time_user,
Scalene.__last_signal_time.virtual,
Scalene.__last_signal_time.wallclock,
Scalene.__last_signal_time.sys,
Scalene.__last_signal_time.user,
Scalene.__is_thread_sleeping,
)
elapsed = now_wallclock - Scalene.__last_signal_time_wallclock
elapsed = now_wallclock - Scalene.__last_signal_time.wallclock
# Store the latest values as the previously recorded values.
Scalene.__last_signal_time_virtual = now_virtual
Scalene.__last_signal_time_wallclock = now_wallclock
Scalene.__last_signal_time_sys = now_sys
Scalene.__last_signal_time_user = now_user
Scalene.__last_signal_time.virtual = now_virtual
Scalene.__last_signal_time.wallclock = now_wallclock
Scalene.__last_signal_time.sys = now_sys
Scalene.__last_signal_time.user = now_user
# Restart the timer while handling any timers set by the client.
if sys.platform != "win32":
if Scalene.client_timer.is_set:
Expand Down Expand Up @@ -1636,15 +1636,10 @@ def disable_signals(retry: bool = True) -> None:
return
try:
Scalene.__orig_setitimer(Scalene.__signals.cpu_timer_signal, 0)
Scalene.__orig_signal(
Scalene.__signals.malloc_signal, signal.SIG_IGN
)
Scalene.__orig_signal(
Scalene.__signals.free_signal, signal.SIG_IGN
)
Scalene.__orig_signal(
Scalene.__signals.memcpy_signal, signal.SIG_IGN
)
for sig in [Scalene.__signals.malloc_signal,
Scalene.__signals.free_signal,
Scalene.__signals.memcpy_signal]:
Scalene.__orig_signal(sig, signal.SIG_IGN)
Scalene.stop_signal_queues()
except Exception:
# Retry just in case we get interrupted by one of our own signals.
Expand Down Expand Up @@ -1809,12 +1804,9 @@ def run_profiler(
Scalene.__signals.stop_profiling_signal,
Scalene.stop_signal_handler,
)
Scalene.__orig_siginterrupt(
Scalene.__signals.start_profiling_signal, False
)
Scalene.__orig_siginterrupt(
Scalene.__signals.stop_profiling_signal, False
)
for sig in [Scalene.__signals.start_profiling_signal,
Scalene.__signals.stop_profiling_signal]:
Scalene.__orig_siginterrupt(sig, False)

Scalene.__orig_signal(signal.SIGINT, Scalene.interruption_handler)
did_preload = (
Expand Down

0 comments on commit fca8de3

Please sign in to comment.