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
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, ), )
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, )
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)")
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, ), )
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)")
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