Ejemplo n.º 1
0
    def __init__(
        self,
        *args,
        gcc_bin: Union[str, Path] = DEFAULT_GCC,
        benchmark: Union[str, Benchmark] = "benchmark://chstone-v0/adpcm",
        datasets_site_path: Optional[Path] = None,
        connection_settings: Optional[ConnectionOpts] = None,
        timeout: Optional[int] = None,
        **kwargs,
    ):
        """Create an environment.

        :param gcc_bin: The path to the GCC executable, or the name of a docker
            image to use if prefixed with :code:`docker:`. Only used if the
            environment is attached to a local service. If attached remotely,
            the service will have already been created.

        :param benchmark: The benchmark to use for this environment. Either a
            URI string, or a :class:`Benchmark
            <compiler_gym.datasets.Benchmark>` instance. If not provided, a
            default benchmark is used.

        :param connection_settings: The connection settings to use.

        :param timeout: The timeout to use when compiling.

        :raises EnvironmentNotSupported: If the runtime requirements for the GCC
            environment have not been met.

        :raises ServiceInitError: If the requested GCC version cannot be used.
        """
        connection_settings = connection_settings or ConnectionOpts()
        # Pass the executable path via an environment variable
        connection_settings.script_env = {"CC": gcc_bin}

        # Eagerly create a GCC compiler instance now because:
        #
        # 1. We want to catch an invalid gcc_bin argument early.
        #
        # 2. We want to perform the expensive one-off `docker pull` before we
        #    start the backend service, as otherwise the backend service
        #    initialization may time out.
        Gcc(bin=gcc_bin)

        super().__init__(
            *args,
            **kwargs,
            benchmark=benchmark,
            datasets=get_gcc_datasets(gcc_bin=gcc_bin,
                                      site_data_base=datasets_site_path),
            rewards=[AsmSizeReward(), ObjSizeReward()],
            connection_settings=connection_settings,
        )
        self._timeout = timeout
Ejemplo n.º 2
0
def test_create_channel_failed_subprocess(
    dead_connection: CompilerGymServiceConnection, ):
    with pytest.raises((ServiceError, TimeoutError),
                       match="Failed to create connection to localhost:"):
        CompilerGymServiceConnection(
            f"{dead_connection.connection.url}",
            ConnectionOpts(
                init_max_seconds=1,
                init_max_attempts=2,
                rpc_init_max_seconds=0.1,
            ),
        )
Ejemplo n.º 3
0
def connection_settings_from_flags(
        service_url: str = None,
        local_service_binary: Path = None) -> ConnectionOpts:
    """Returns either the name of the benchmark, or a Benchmark message."""
    return ConnectionOpts(
        rpc_call_max_seconds=FLAGS.service_rpc_call_max_seconds,
        init_max_seconds=FLAGS.service_init_max_seconds,
        init_max_attempts=FLAGS.service_init_max_attempts,
        local_service_port_init_max_seconds=FLAGS.
        local_service_port_init_max_seconds,
        local_service_exit_max_seconds=FLAGS.local_service_exit_max_seconds,
        rpc_init_max_seconds=FLAGS.service_rpc_init_max_seconds,
    )
Ejemplo n.º 4
0
def test_create_channel_failed_subprocess(
    dead_connection: CompilerGymServiceConnection, ):
    with pytest.raises(OSError) as ctx:
        CompilerGymServiceConnection(
            f"{dead_connection.connection.url}",
            ConnectionOpts(
                init_max_seconds=1,
                init_max_attempts=2,
                rpc_init_max_seconds=0.1,
            ),
        )

    assert str(
        ctx.value).startswith("Failed to create connection to localhost:")
    assert str(ctx.value).endswith(" (2/2 attempts made)")
Ejemplo n.º 5
0
def test_create_channel_failed_subprocess_rpc_timeout(
    dead_connection: CompilerGymServiceConnection, ):
    """Same as the above test, but RPC timeout is long enough that only a single
    attempt can be made.
    """
    with pytest.raises(
            OSError,
            match=(r"Failed to create connection to localhost:\d+ after "
                   r"[\d\.]+ seconds \(1 attempt made\)"),
    ):
        CompilerGymServiceConnection(
            f"{dead_connection.connection.url}",
            ConnectionOpts(
                init_max_seconds=0.1,
                init_max_attempts=2,
                rpc_init_max_seconds=1,
            ),
        )
Ejemplo n.º 6
0
def test_create_channel_failed_subprocess_rpc_timeout(
    dead_connection: CompilerGymServiceConnection, ):
    """Same as the above test, but RPC timeout is long enough that only a single
    attempt can be made.
    """
    with pytest.raises(OSError) as ctx:
        CompilerGymServiceConnection(
            f"{dead_connection.connection.url}",
            ConnectionOpts(
                init_max_seconds=0.1,
                init_max_attempts=2,
                rpc_init_max_seconds=1,
            ),
        )

    assert str(
        ctx.value).startswith("Failed to create connection to localhost:")
    assert str(ctx.value).endswith(" (1/2 attempts made)")
Ejemplo n.º 7
0
    def __init__(
        self,
        service: Union[str, Path],
        benchmark: Optional[Union[str, Benchmark]] = None,
        observation_space: Optional[str] = None,
        reward_space: Optional[str] = None,
        action_space: Optional[str] = None,
        connection_settings: Optional[ConnectionOpts] = None,
    ):
        """Construct and initialize a CompilerGym service environment.

        :param service: The hostname and port of a service that implements the
            CompilerGym service interface, or the path of a binary file
            which provides the CompilerGym service interface when executed.
            See :doc:`/compiler_gym/service` for details.
        :param benchmark: The name of the benchmark to use for this environment.
            The choice of benchmark can be deferred by not providing this
            argument and instead passing by choosing from the
            :code:`CompilerEnv.benchmarks` attribute and passing it to
            :func:`reset()` when called.
        :param observation_space: Compute and return observations at each
            :func:`step()` from this space. If not provided, :func:`step()`
            returns :code:`None` for the observation value.
        :param reward_space: Compute and return reward at each :func:`step()`
            from this space. If not provided, :func:`step()` returns
            :code:`None` for the reward value.
        :param action_space: The name of the action space to use. If not
            specified, the default action space for this compiler is used.
        :raises FileNotFoundError: If service is a path to a file that is not
            found.
        :raises TimeoutError: If the compiler service fails to initialize
            within the parameters provided in :code:`connection_settings`.
        """
        self.metadata = {"render.modes": ["human", "ansi"]}

        self.service_endpoint = service
        self.connection_settings = connection_settings or ConnectionOpts()
        self.datasets_site_path: Optional[Path] = None
        self.available_datasets: Dict[str, Dataset] = {}

        # The benchmark that is currently being used, and the benchmark that
        # the user requested. Those do not always correlate, since the user
        # could request a random benchmark.
        self._benchmark_in_use_uri: Optional[str] = None
        self._user_specified_benchmark_uri: Optional[str] = None
        # A map from benchmark URIs to Benchmark messages. We keep track of any
        # user-provided custom benchmarks so that we can register them with a
        # reset service.
        self._custom_benchmarks: Dict[str, Benchmark] = {}

        self.action_space_name = action_space

        self.service = CompilerGymServiceConnection(self.service_endpoint,
                                                    self.connection_settings)

        # Process the available action, observation, and reward spaces.
        self.action_spaces = [
            self._make_action_space(space.name, space.action)
            for space in self.service.action_spaces
        ]
        self.observation = self._observation_view_type(
            get_observation=lambda req: self.service(
                self.service.stub.GetObservation, req),
            spaces=self.service.observation_spaces,
        )
        self.reward = self._reward_view_type(
            get_reward=lambda req: self.service(self.service.stub.GetReward,
                                                req),
            spaces=self.service.reward_spaces,
        )

        # Lazily evaluated version strings.
        self._versions: Optional[GetVersionReply] = None

        # A compiler service supports multiple simultaneous environments. This
        # session ID is used to identify this environment.
        self._session_id: Optional[int] = None

        # Mutable state initialized in reset().
        self.action_space: Optional[Space] = None
        self.observation_space: Optional[Space] = None
        self.reward_range: Tuple[float, float] = (-np.inf, np.inf)

        # Initialize eager observation/reward and benchmark.
        self.observation_space = observation_space
        self.reward_space = reward_space
        self.benchmark = benchmark