diff --git a/alf/environments/dmc_gym_wrapper.py b/alf/environments/dmc_gym_wrapper.py index 1c68cc090..ca33fa019 100644 --- a/alf/environments/dmc_gym_wrapper.py +++ b/alf/environments/dmc_gym_wrapper.py @@ -16,6 +16,43 @@ """ from functools import partial +import ctypes +import os +import subprocess +import sys + +# Preload GLFW library on macOS before importing dm_control/glfw +if sys.platform == 'darwin': + glfw_lib_path = None + # Check common Homebrew locations + for lib_dir in ['/opt/homebrew/lib', '/usr/local/lib']: + candidate = os.path.join(lib_dir, 'libglfw.dylib') + if os.path.exists(candidate): + glfw_lib_path = candidate + break + # Fall back to brew --prefix + if glfw_lib_path is None: + try: + result = subprocess.run(['brew', '--prefix', 'glfw'], + capture_output=True, + text=True) + if result.returncode == 0: + candidate = os.path.join(result.stdout.strip(), 'lib', + 'libglfw.dylib') + if os.path.exists(candidate): + glfw_lib_path = candidate + except Exception: + pass + # Tell glfw Python package where to find the library + if glfw_lib_path is None: + raise ImportError( + "Could not find libglfw.dylib on macOS. " + "Install with: brew install glfw && pip install glfw") + os.environ['PYGLFW_LIBRARY'] = glfw_lib_path + try: + ctypes.CDLL(glfw_lib_path, mode=ctypes.RTLD_GLOBAL) + except OSError as e: + raise ImportError(f"Failed to load {glfw_lib_path}: {e}") import gym from gym import spaces @@ -23,12 +60,12 @@ import numpy as np from typing import Dict, Optional, Any -try: - import dm_control - from dm_control import suite - import dm_env -except ImportError: - dm_control = None +# try: +import dm_control +from dm_control import suite +import dm_env +# except ImportError: +# dm_control = None def _dmc_spec_to_box(spec): diff --git a/alf/environments/process_environment.py b/alf/environments/process_environment.py index ef182caed..70cb513ab 100644 --- a/alf/environments/process_environment.py +++ b/alf/environments/process_environment.py @@ -23,6 +23,7 @@ from functools import partial import multiprocessing import os +import subprocess import sys import threadpoolctl import torch @@ -39,12 +40,23 @@ import pathlib DIR = pathlib.Path(__file__).parent.absolute() +boost_include = os.path.join(os.path.expanduser('~'), + 'opt/homebrew/opt/boost/include') +if not os.path.exists(boost_include): + brew_boost = subprocess.run(['brew', '--prefix', 'boost'], + capture_output=True, + text=True) + if brew_boost.returncode == 0: + boost_include = os.path.join(brew_boost.stdout.strip(), 'include') +extra_cflags = [ + '-O3', '-Wall', '-shared', '-std=c++17', '-fPIC', '-fvisibility=hidden' +] +if os.path.exists(boost_include): + extra_cflags.append(f'-I{boost_include}') _penv = lazy_load_extension( name="penv", sources=[os.path.join(DIR, "parallel_environment.cpp")], - extra_cflags=[ - '-O3', '-Wall', '-shared', '-std=c++17', '-fPIC', '-fvisibility=hidden' - ], + extra_cflags=extra_cflags, verbose=True) FLAGS = flags.FLAGS diff --git a/alf/networks/preprocessors.py b/alf/networks/preprocessors.py index f61408c7b..21a524b6b 100644 --- a/alf/networks/preprocessors.py +++ b/alf/networks/preprocessors.py @@ -105,7 +105,7 @@ def forward(self, inputs, state=()): Tensor or TensorSpec: if ``Tensor``, the returned is the preprocessed result; otherwise it's the tensor spec of the result. """ - assert state is (), \ + assert state == (), \ "The preprocessor is assumed to be stateless currently." ret = self._preprocess(inputs) diff --git a/alf/trainers/policy_trainer.py b/alf/trainers/policy_trainer.py index 7454a2810..1f6ef080d 100644 --- a/alf/trainers/policy_trainer.py +++ b/alf/trainers/policy_trainer.py @@ -22,7 +22,6 @@ import os from pathlib import Path import re -import signal import threading import sys from typing import Callable @@ -324,31 +323,7 @@ def train(self): self._checkpoint_requested = False self._evaluation_requested = False - if threading.current_thread() == threading.main_thread(): - signal.signal(signal.SIGUSR2, self._request_checkpoint) - # kill -12 PID - logging.info( - "Use `kill -%s %s` to request checkpoint during training." % - (int(signal.SIGUSR2), self._pid)) - self._video_clip_requested = False - if threading.current_thread() == threading.main_thread(): - signal.signal(signal.SIGRTMIN, self._request_video_clip) - # kill -34 PID - logging.info( - ("Use `kill -%s %s` to request video-clip during training. " - f"The videos will be saved at `{self._train_dir}/train/video/" - ) % (int(signal.SIGRTMIN), self._pid)) - - if (threading.current_thread() == threading.main_thread() - and PerProcessContext().ddp_rank <= 0): - # Debugging in subprocesses is not supported because they don't have - # stdin. - # kill -10 PID - signal.signal(signal.SIGUSR1, self._request_debug) - logging.info("Use `kill -%s %s` to request debugging." % - (int(signal.SIGUSR1), self._pid)) - checkpoint_saved = False try: if self._config.profiling: diff --git a/alf/utils/common.py b/alf/utils/common.py index 3153a2cfd..d05d78157 100644 --- a/alf/utils/common.py +++ b/alf/utils/common.py @@ -16,6 +16,7 @@ from absl import flags from absl import logging import contextlib +import platform import copy import ctypes import ctypes.util @@ -109,6 +110,8 @@ def allow_child_to_ptrace(child_pid: int) -> None: cat /proc/sys/kernel/yama/ptrace_scope """ + if platform.system() != "Linux": + return libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)