diff --git a/src/sinol_make/__init__.py b/src/sinol_make/__init__.py index a02138a2..53f1f332 100644 --- a/src/sinol_make/__init__.py +++ b/src/sinol_make/__init__.py @@ -38,7 +38,7 @@ def configure_parsers(): def check_sio2jail(): - if util.is_linux() and not sio2jail.check_sio2jail(): + if sio2jail.sio2jail_supported() and not sio2jail.check_sio2jail(): print(util.warning('Up to date `sio2jail` in `~/.local/bin/` not found, installing new version...')) try: if sio2jail.install_sio2jail(): diff --git a/src/sinol_make/commands/run/__init__.py b/src/sinol_make/commands/run/__init__.py index f4134026..81f673c9 100644 --- a/src/sinol_make/commands/run/__init__.py +++ b/src/sinol_make/commands/run/__init__.py @@ -280,7 +280,7 @@ def configure_subparser(self, subparser): After running the solutions, it compares the solutions\' scores with the ones saved in config.yml.' ) - default_timetool = 'sio2jail' if util.is_linux() else 'time' + default_timetool = 'sio2jail' if sio2jail.sio2jail_supported() else 'time' parser.add_argument('-s', '--solutions', type=str, nargs='+', help='solutions to be run, for example prog/abc{b,s}*.{cpp,py}') @@ -764,7 +764,7 @@ def validate_arguments(self, args): def use_sio2jail(): timetool_path = None - if not util.is_linux(): + if not sio2jail.sio2jail_supported(): util.exit_with_error('As `sio2jail` works only on Linux-based operating systems,\n' 'we do not recommend using operating systems such as macOS.\n' 'Nevertheless, you can still run sinol-make by specifying\n' @@ -789,12 +789,12 @@ def use_time(): timetool_path, timetool_name = None, None preferred_timetool = self.contest.preferred_timetool() - if preferred_timetool == 'sio2jail' and util.is_linux(): + if preferred_timetool == 'sio2jail' and sio2jail.sio2jail_supported(): use_default_timetool = use_sio2jail elif preferred_timetool == 'time': use_default_timetool = use_time else: - use_default_timetool = use_sio2jail if util.is_linux() else use_time + use_default_timetool = use_sio2jail if sio2jail.sio2jail_supported() else use_time if args.time_tool is None and self.config.get('sinol_undocumented_time_tool', '') != '': if self.config.get('sinol_undocumented_time_tool', '') == 'sio2jail': diff --git a/src/sinol_make/sio2jail/__init__.py b/src/sinol_make/sio2jail/__init__.py index a1dc03eb..4a70af5c 100644 --- a/src/sinol_make/sio2jail/__init__.py +++ b/src/sinol_make/sio2jail/__init__.py @@ -74,12 +74,14 @@ def install_sio2jail(directory=None): def check_perf_counters_enabled(): """ - Checks if `kernel.perf_event_paranoid` is set to -1. - :return: + Checks if sio2jail is able to use perf counters to count instructions. """ - if not util.is_linux() or not check_sio2jail(): + if not sio2jail_supported() or not check_sio2jail(): return + with open('/proc/sys/kernel/perf_event_paranoid') as f: + perf_event_paranoid = int(f.read()) + sio2jail = get_default_sio2jail_path() test_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'perf_test.py') python_executable = sys.executable @@ -94,9 +96,21 @@ def check_perf_counters_enabled(): process.terminate() if output != "Test string\n": - util.exit_with_error("To use the recommended tool for measuring time called `sio2jail`, please:\n" - "- execute `sudo sysctl kernel.perf_event_paranoid=-1` to make `sio2jail` work for\n" - " the current system session,\n" - "- or add `kernel.perf_event_paranoid=-1` to `/etc/sysctl.conf`\n" - " and reboot to permanently make sio2jail work.\n" - "For more details, see https://github.com/sio2project/sio2jail#running.\n") + max_perf_event_paranoid = 2 + if perf_event_paranoid > max_perf_event_paranoid: + hint = (f"You have `kernel.perf_event_paranoid` set to `{perf_event_paranoid}`" + ", which might be preventing userspace perf counters from working.\n" + f"Try running: `sudo sysctl kernel.perf_event_paranoid={max_perf_event_paranoid}`\n" + "If that fixes the problem, you can set this permanently by adding " + f"`kernel.perf_event_paranoid={max_perf_event_paranoid}` to `/etc/sysctl.conf` and rebooting.\n") + else: + hint = ("Your kernel, drivers, or hardware might be too old.\n" + "Check if the Intel PMU driver is loaded: `dmesg | grep -i 'perf'`\n" + "You can also check if the perf tool works correctly: `perf stat -e instructions:u -- sleep 0`\n" + "(if perf can't be found, it might be located in: `/usr/lib/linux-tools/*/perf`).\n") + cmdline = " ".join(process.args) + util.exit_with_error(f"Failed performance counters test: `{cmdline}`\n" + + hint + + "Alternatively, you can run sinol-make without instruction counting" + ", by adding the `--time-tool time` flag.\n" + "For more details, see https://github.com/sio2project/sio2jail#running.\n") diff --git a/src/sinol_make/util.py b/src/sinol_make/util.py index 04733db8..6f330a45 100644 --- a/src/sinol_make/util.py +++ b/src/sinol_make/util.py @@ -321,9 +321,9 @@ def is_wsl(): def is_linux(): """ - Function to check if the program is running on Linux and not WSL. + Function to check if the program is running on Linux (including WSL). """ - return sys.platform == "linux" and not is_wsl() + return sys.platform == "linux" def is_macos(): diff --git a/tests/conftest.py b/tests/conftest.py index 9683c6fe..e42622bb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,7 @@ import fnmatch import multiprocessing as mp -from sinol_make import util +from sinol_make import sio2jail, util from sinol_make.helpers import compile, paths, cache, oicompare from sinol_make.interfaces.Errors import CompilationError @@ -99,7 +99,7 @@ def pytest_generate_tests(metafunc): time_tools = [] if metafunc.config.getoption("time_tool") != []: time_tools = metafunc.config.getoption("time_tool") - elif util.is_linux(): + elif sio2jail.sio2jail_supported(): time_tools = ["sio2jail", "time"] else: time_tools = ["time"] @@ -118,6 +118,6 @@ def pytest_collection_modifyitems(config, items: List[pytest.Item]): for item in items: if "sio2jail" in item.keywords: - if not util.is_linux() or config.getoption("--time-tool") == ["time"] or \ + if not sio2jail.sio2jail_supported() or config.getoption("--time-tool") == ["time"] or \ config.getoption("--github-runner"): item.add_marker(pytest.mark.skip(reason="sio2jail required")) diff --git a/tests/test_sio2jail.py b/tests/test_sio2jail.py index da193d17..d54ac15f 100644 --- a/tests/test_sio2jail.py +++ b/tests/test_sio2jail.py @@ -9,7 +9,7 @@ @pytest.mark.github_runner def test_install_sio2jail(): - if sys.platform != 'linux': + if not sio2jail.sio2jail_supported(): return try: @@ -34,7 +34,7 @@ def test_install_sio2jail(): @pytest.mark.github_runner def test_check_sio2jail(): - if sys.platform != 'linux': + if not sio2jail.sio2jail_supported(): return try: @@ -59,7 +59,7 @@ def test_perf_counters_not_set(): """ Test `sio2jail.check_perf_counters_enabled` with perf counters disabled """ - if sys.platform != 'linux': + if not sio2jail.sio2jail_supported(): return sio2jail.install_sio2jail() @@ -72,7 +72,7 @@ def test_perf_counters_set(): """ Test `sio2jail.check_perf_counters_enabled` with perf counters enabled """ - if not util.is_linux(): + if not sio2jail.sio2jail_supported(): return sio2jail.check_perf_counters_enabled() @@ -82,7 +82,7 @@ def test_updating(): """ Test updating sio2jail """ - if sys.platform != 'linux': + if not sio2jail.sio2jail_supported(): return try: os.remove(os.path.expanduser('~/.local/bin/oiejq'))