compiler_gym.service

The compiler_gym.service module provides a client/service implementation of the CompilerEnv interface. Services provide an interface for manipulating compiler behavior. Clients are Python frontend objects that provide a reinforcement learning abstraction on top of the service. Communication between the service and client is done using RPC. The connection between the client and service is managed by the CompilerGymServiceConnection object.

The CompilationSession Interface

class compiler_gym.service.CompilationSession(working_dir: Path, action_space: ActionSpace, benchmark: Benchmark)[source]

Base class for encapsulating an incremental compilation session.

To add support for a new compiler, subclass from this base and provide implementations of the abstract methods, then call create_and_run_compiler_service and pass in your class type:

from compiler_gym.service import CompilationSession
from compiler_gym.service import runtime

class MyCompilationSession(CompilationSession):
    ...

if __name__ == "__main__":
    runtime.create_and_run_compiler_service(MyCompilationSession)
__init__(working_dir: Path, action_space: ActionSpace, benchmark: Benchmark)[source]

Start a CompilationSession.

Subclasses should initialize the parent class first.

Parameters
  • working_dir – A directory on the local filesystem that can be used to store temporary files such as build artifacts.

  • action_space – The action space to use.

  • benchmark – The benchmark to use.

action_spaces: List[ActionSpace] = []

A list of action spaces describing the capabilities of the compiler.

apply_action(action: Event) Tuple[bool, Optional[ActionSpace], bool][source]

Apply an action.

Parameters

action – The action to apply.

Returns

A tuple: :code:`(end_of_session, new_action_space,

action_had_no_effect)`.

compiler_version: str = ''

The compiler version.

fork() CompilationSession[source]

Create a copy of current session state.

Implementing this method is optional.

Returns

A new CompilationSession with the same state.

get_observation(observation_space: ObservationSpace) Event[source]

Compute an observation.

Parameters

observation_space – The observation space.

Returns

An observation.

handle_session_parameter(key: str, value: str) Optional[str][source]

Handle a session parameter send by the frontend.

Session parameters provide a method to send ad-hoc key-value messages to a compilation session through the env.send_session_parameter() method. It us up to the client/service to agree on a common schema for encoding and decoding these parameters.

Implementing this method is optional.

Parameters
  • key – The parameter key.

  • value – The parameter value.

Returns

A string response message if the parameter was understood. Else None to indicate that the message could not be interpretted.

observation_spaces: List[ObservationSpace] = []

A list of feature vectors that this compiler provides.

ClientServiceCompilerEnv

class compiler_gym.service.client_service_compiler_env.ClientServiceCompilerEnv(service: Union[str, Path], rewards: Optional[List[Reward]] = None, datasets: Optional[Iterable[Dataset]] = None, benchmark: Optional[Union[str, Benchmark]] = None, observation_space: Optional[Union[str, ObservationSpaceSpec]] = None, reward_space: Optional[Union[str, Reward]] = None, action_space: Optional[str] = None, derived_observation_spaces: Optional[List[Dict[str, Any]]] = None, service_message_converters: Optional[ServiceMessageConverters] = None, connection_settings: Optional[ConnectionOpts] = None, service_connection: Optional[CompilerGymServiceConnection] = None)[source]

Implementation of CompilerEnv using gRPC for client-server communication.

Variables

service (compiler_gym.service.CompilerGymServiceConnection) – A connection to the underlying compiler service.

__init__(service: Union[str, Path], rewards: Optional[List[Reward]] = None, datasets: Optional[Iterable[Dataset]] = None, benchmark: Optional[Union[str, Benchmark]] = None, observation_space: Optional[Union[str, ObservationSpaceSpec]] = None, reward_space: Optional[Union[str, Reward]] = None, action_space: Optional[str] = None, derived_observation_spaces: Optional[List[Dict[str, Any]]] = None, service_message_converters: Optional[ServiceMessageConverters] = None, connection_settings: Optional[ConnectionOpts] = None, service_connection: Optional[CompilerGymServiceConnection] = None)[source]

Construct and initialize a CompilerGym environment.

In normal use you should use gym.make(...) rather than calling the constructor directly.

Parameters
  • 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 compiler_gym.service for details.

  • rewards – The reward spaces that this environment supports. Rewards are typically calculated based on observations generated by the service. See Reward for details.

  • benchmark – The benchmark to use for this environment. Either a URI string, or a Benchmark instance. If not provided, the first benchmark as returned by next(env.datasets.benchmarks()) will be used as the default.

  • observation_space – Compute and return observations at each step() from this space. Accepts a string name or an ObservationSpaceSpec. If not provided, step() returns None for the observation value. Can be set later using env.observation_space. For available spaces, see env.observation.spaces.

  • reward_space – Compute and return reward at each step() from this space. Accepts a string name or a Reward. If not provided, step() returns None for the reward value. Can be set later using env.reward_space. For available spaces, see env.reward.spaces.

  • action_space – The name of the action space to use. If not specified, the default action space for this compiler is used.

  • derived_observation_spaces – An optional list of arguments to be passed to env.observation.add_derived_space().

  • service_message_converters – Custom converters for action spaces and actions.

  • connection_settings – The settings used to establish a connection with the remote service.

  • service_connection – An existing compiler gym service connection to use.

Raises
  • FileNotFoundError – If service is a path to a file that is not found.

  • TimeoutError – If the compiler service fails to initialize within the parameters provided in connection_settings.

property action_space: ActionSpace

The current action space.

Getter

Get the current action space.

Setter

Set the action space to use. Must be an entry in action_spaces. If None, the default action space is selected.

property action_spaces: List[str]

A list of supported action space names.

apply(state: CompilerEnvState) None[source]

Replay this state on the given environment.

Parameters

state – A CompilerEnvState instance.

Raises

ValueError – If this state cannot be applied.

property benchmark: Benchmark

Get or set the benchmark to use.

Getter

Get Benchmark that is currently in use.

Setter

Set the benchmark to use. Either a Benchmark instance, or the URI of a benchmark as in env.datasets.benchmark_uris().

Note

Setting a new benchmark has no effect until env.reset() is called.

close()[source]

Close the environment.

Once closed, reset() must be called before the environment is used again.

Note

You must make sure to call env.close() on a CompilerGym environment when you are done with it. This is needed to perform manual tidying up of temporary files and processes. See the FAQ for more details.

commandline() str[source]

Calling this method on a ClientServiceCompilerEnv instance raises NotImplementedError.

commandline_to_actions(commandline: str) List[ActionType][source]

Calling this method on a ClientServiceCompilerEnv instance raises NotImplementedError.

property compiler_version: str

The version string of the underlying compiler that this service supports.

property episode_reward: Optional[float]

CompilerEnv.reward_space <compiler_gym.envs.CompilerGym.reward_space> is set, this value is the sum of all rewards for the current episode.

Type

If

Type

func

property episode_walltime: float

Return the amount of time in seconds since the last call to reset().

fork() ClientServiceCompilerEnv[source]

Fork a new environment with exactly the same state.

This creates a duplicate environment instance with the current state. The new environment is entirely independently of the source environment. The user must call close() on the original and new environments.

If not already in an episode, reset() is called.

Example usage:

>>> env = gym.make("llvm-v0")
>>> env.reset()
# ... use env
>>> new_env = env.fork()
>>> new_env.state == env.state
True
>>> new_env.step(1) == env.step(1)
True

Note

The client/service implementation of CompilerGym means that the forked and base environments share a common backend resource. This means that if either of them crash, such as due to a compiler assertion, both environments must be reset.

Returns

A new environment instance.

property in_episode: bool

Whether the service is ready for step() to be called, i.e. reset() has been called and close() has not.

Returns

True if in an episode, else False.

multistep(actions: Iterable[ActionType], observation_spaces: Optional[Iterable[Union[str, ObservationSpaceSpec]]] = None, reward_spaces: Optional[Iterable[Union[str, Reward]]] = None, observations: Optional[Iterable[Union[str, ObservationSpaceSpec]]] = None, rewards: Optional[Iterable[Union[str, Reward]]] = None, timeout: float = 300)[source]
Raises

SessionNotFound – If :meth:`reset()

<compiler_gym.envs.ClientServiceCompilerEnv.reset>` has not been called.

property observation: ObservationView

A view of the available observation spaces that permits on-demand computation of observations.

property observation_space: Optional[Space]

The observation space that is used to return an observation value in step().

Getter

Returns the underlying observation space, or None if not set.

Setter

Set the default observation space.

raw_step(actions: Iterable[ActionType], observation_spaces: List[ObservationSpaceSpec], reward_spaces: List[Reward], timeout: float = 300) Tuple[Optional[Union[ObservationType, List[ObservationType]]], Optional[Union[float, List[float]]], bool, Dict[str, Any]][source]

Take a step.

Parameters
  • actions – A list of actions to be applied.

  • observations – A list of observations spaces to compute observations from. These are evaluated after the actions are applied.

  • rewards – A list of reward spaces to compute rewards from. These are evaluated after the actions are applied.

Returns

A tuple of observations, rewards, done, and info. Observations and rewards are lists.

Raises

SessionNotFound – If reset() has not been called.

Warning

Don’t call this method directly, use step() or multistep() instead. The raw_step() method is an implementation detail.

render(mode='human') Optional[str][source]

Render the environment.

ClientServiceCompilerEnv instances support two render modes: “human”, which prints the current environment state to the terminal and return nothing; and “ansi”, which returns a string representation of the current environment state.

Parameters

mode – The render mode to use.

Raises

TypeError – If a default observation space is not set, or if the requested render mode does not exist.

reset(benchmark: Optional[Union[str, Benchmark]] = None, action_space: Optional[str] = None, reward_space: Union[OptionalArgumentValue, str, Reward] = OptionalArgumentValue.UNCHANGED, observation_space: Union[OptionalArgumentValue, str, ObservationSpaceSpec] = OptionalArgumentValue.UNCHANGED, timeout: float = 300) Optional[ObservationType][source]

Reset the environment state.

This method must be called before step().

Parameters
  • benchmark – The name of the benchmark to use. If provided, it overrides any value that was set during __init__(), and becomes subsequent calls to reset() will use this benchmark. If no benchmark is provided, and no benchmark was provided to __init___(), the service will randomly select a benchmark to use.

  • action_space – The name of the action space to use. If provided, it overrides any value that set during __init__(), and subsequent calls to reset() will use this action space. If no action space is provided, the default action space is used.

  • observation_space – Compute and return observations at each step() from this space. Accepts a string name or an ObservationSpaceSpec. If None, step() returns None for the observation value. If OptionalArgumentValue.UNCHANGED (the default value), the observation space remains unchanged from the previous episode. For available spaces, see env.observation.spaces.

  • reward_space – Compute and return reward at each step() from this space. Accepts a string name or a Reward. If None, step() returns None for the reward value. If OptionalArgumentValue.UNCHANGED (the default value), the observation space remains unchanged from the previous episode. For available spaces, see env.reward.spaces.

  • timeout – The maximum number of seconds to wait for reset to succeed.

Returns

The initial observation.

Raises
  • BenchmarkInitError – If the benchmark is invalid. This can happen if the benchmark contains code that the compiler does not support, or because of some internal error within the compiler. In this case, another benchmark must be used.

  • TypeError – If no benchmark has been set, and the environment does not have a default benchmark to select from.

property reward: RewardView

A view of the available reward spaces that permits on-demand computation of rewards.

property reward_range: Tuple[float, float]

A tuple indicating the range of reward values.

Default range is (-inf, +inf).

property reward_space: Optional[Reward]

The default reward space that is used to return a reward value from step().

Getter

Returns a Reward, or None if not set.

Setter

Set the default reward space.

send_param(key: str, value: str, resend_on_reset: bool = False) str[source]

Send a single <key, value> parameter to the compiler service.

See send_params() for more information.

Parameters
  • key – The parameter key.

  • value – The parameter value.

  • resend_on_reset – Whether to resend this parameter to the compiler service on reset().

Returns

The response from the compiler service.

Raises

SessionNotFound – If called before reset().

send_params(*params: Iterable[Tuple[str, str]], resend_on_reset: bool = False) List[str][source]

Send a list of <key, value> parameters to the compiler service.

This provides a mechanism to send messages to the backend compilation session in a way that doesn’t conform to the normal communication pattern. This can be useful for things like configuring runtime debugging settings, or applying “meta actions” to the compiler that are not exposed in the compiler’s action space. Consult the documentation for a specific compiler service to see what parameters, if any, are supported.

Must have called reset() first.

Parameters
  • params – A list of parameters, where each parameter is a (key, value) tuple.

  • resend_on_reset – Whether to resend this parameter to the compiler service on reset().

Returns

A list of string responses, one per parameter.

Raises

SessionNotFound – If called before reset().

property state: CompilerEnvState

The tuple representation of the current environment state.

step(action: ActionType, observation_spaces: Optional[Iterable[Union[str, ObservationSpaceSpec]]] = None, reward_spaces: Optional[Iterable[Union[str, Reward]]] = None, observations: Optional[Iterable[Union[str, ObservationSpaceSpec]]] = None, rewards: Optional[Iterable[Union[str, Reward]]] = None, timeout: float = 300) Tuple[Optional[Union[ObservationType, List[ObservationType]]], Optional[Union[float, List[float]]], bool, Dict[str, Any]][source]
Raises

SessionNotFound – If :meth:`reset()

<compiler_gym.envs.ClientServiceCompilerEnv.reset>` has not been called.

validate(state: Optional[CompilerEnvState] = None) ValidationResult[source]

Validate an environment’s state.

Parameters

state – A state to environment. If not provided, the current state is validated.

Returns

A ValidationResult.

property version: str

The version string of the compiler service.

property versions: GetVersionReply

Get the version numbers from the compiler service.

class compiler_gym.service.client_service_compiler_env.ServiceMessageConverters(action_space_converter: Optional[Callable[[ActionSpace], Space]] = None, action_converter: Optional[Callable[[Any], Event]] = None)[source]

Allows for customization of conversion to/from gRPC messages for the ClientServiceCompilerEnv.

Supports conversion customizations:

  • compiler_gym.service.proto.ActionSpace -> gym.spaces.Space.

  • compiler_gym.util.gym_type_hints.ActionType -> compiler_gym.service.proto.Event.

__init__(action_space_converter: Optional[Callable[[ActionSpace], Space]] = None, action_converter: Optional[Callable[[Any], Event]] = None)[source]

Constructor.

The connection object

class compiler_gym.service.CompilerGymServiceConnection(endpoint: Union[str, Path], opts: Optional[ConnectionOpts] = None)[source]

A connection to a compiler gym service.

There are two types of service connections: managed and unmanaged. The type of connection is determined by the endpoint. If a “host:port” URL is provided, an unmanaged connection is created. If the path of a file is provided, a managed connection is used. The difference between a managed and unmanaged connection is that with a managed connection, the lifecycle of the service if controlled by the client connection. That is, when a managed connection is created, a service subprocess is started by executing the specified path. When the connection is closed, the subprocess is terminated. With an unmanaged connection, if the service fails is goes offline, the client will fail.

This class provides a common abstraction between the two types of connection, and provides a call method for invoking remote procedures on the service.

Example usage of an unmanaged service connection:

# Connect to a service running on localhost:8080. The user must
# started a process running on port 8080.
connection = CompilerGymServiceConnection("localhost:8080")
# Invoke an RPC method.
connection(connection.stub.StartSession, StartSessionRequest())
# Close the connection. The service running on port 8080 is
# left running.
connection.close()

Example usage of a managed service connection:

# Start a subprocess using the binary located at /path/to/my/service.
connection = CompilerGymServiceConnection(Path("/path/to/my/service"))
# Invoke an RPC method.
connection(connection.stub.StartSession, StartSessionRequest())
# Close the connection. The subprocess is terminated.
connection.close()
Variables
  • stub – A CompilerGymServiceStub that can be used as the first argument to __call__() to specify an RPC method to call.

  • action_spaces – A list of action spaces provided by the service.

  • observation_spaces – A list of observation spaces provided by the service.

__init__(endpoint: Union[str, Path], opts: Optional[ConnectionOpts] = None)[source]

Constructor.

Parameters
  • endpoint – The connection endpoint. Either the URL of a service, e.g. “localhost:8080”, or the path of a local service binary.

  • opts – The connection options.

Raises
  • ValueError – If the provided options are invalid.

  • FileNotFoundError – In case opts.local_service_binary is not found.

  • TimeoutError – In case the service failed to start within opts.init_max_seconds seconds.

__call__(stub_method: StubMethod, request: Request, timeout: Optional[float] = 300, max_retries: Optional[int] = None, retry_wait_seconds: Optional[float] = None, retry_wait_backoff_exponent: Optional[float] = None) Reply[source]

Invoke an RPC method on the service and return its response. All RPC methods accept a single request message, and respond with a response message.

Example usage:

connection = CompilerGymServiceConnection("localhost:8080")
request = compiler_gym.service.proto.GetSpacesRequest()
reply = connection(connection.stub.GetSpaces, request)

In the above example, the GetSpaces RPC method is invoked on a connection, yielding a GetSpacesReply message.

Parameters
  • stub_method – An RPC method attribute on CompilerGymServiceStub.

  • request – A request message.

  • timeout – The maximum number of seconds to await a reply.

  • max_retries – The maximum number of failed attempts to communicate with the RPC service before raising an error. Retries are made only for communication errors. Failures from other causes such as error signals raised by the service are not retried.

  • retry_wait_seconds – The number of seconds to wait between successive attempts to communicate with the RPC service.

  • retry_wait_backoff_exponent – The exponential backoff scaling between successive attempts to communicate with the RPC service.

Raises
  • ValueError – If the service responds with an error indicating an invalid argument.

  • NotImplementedError – If the service responds with an error indicating that the requested functionality is not implemented.

  • FileNotFoundError – If the service responds with an error indicating that a requested resource was not found.

  • OSError – If the service responds with an error indicating that it ran out of resources.

  • TypeError – If the provided request parameter is of incorrect type or cannot be serialized, or if the service responds with an error indicating that a precondition failed.

  • TimeoutError – If the service failed to respond to the query within the specified timeout.

  • ServiceTransportError – If the client failed to communicate with the service.

  • ServiceIsClosed – If the connection to the service is closed.

  • ServiceError – If the service raised an error not covered by any of the above conditions.

Returns

A reply message.

property closed: bool

Whether the connection is closed.

restart()[source]

Restart a connection a service. If the service is managed by this connection (i.e. it is a local binary), the existing service process will be killed and replaced. Else, only the connection to the unmanaged service process is replaced.

Configuring the connection

The ConnectionOpts object is used to configure the options used for managing a service connection.

class compiler_gym.service.ConnectionOpts(*, rpc_max_retries: int = 5, retry_wait_seconds: float = 0.1, retry_wait_backoff_exponent: float = 1.5, init_max_seconds: float = 30, init_max_attempts: int = 5, local_service_port_init_max_seconds: float = 30, local_service_exit_max_seconds: float = 30, rpc_init_max_seconds: float = 3, always_send_benchmark_on_reset: bool = False, script_args: List[str] = [], script_env: Dict[str, str] = {})[source]

The options used to configure a connection to a service.

always_send_benchmark_on_reset: bool

Send the full benchmark program data to the compiler service on ever call to env.reset(). This is more efficient in cases where the majority of calls to env.reset() uses a different benchmark. In case of benchmark re-use, leave this False.

init_max_attempts: int

The maximum number of attempts to make to establish a connection to the service before failing.

init_max_seconds: float

The maximum number of seconds to spend attempting to establish a connection to the service before failing.

local_service_exit_max_seconds: float

The maximum number of seconds to wait for a local service to terminate on close.

local_service_port_init_max_seconds: float

The maximum number of seconds to wait for a local service to write the port.txt file.

retry_wait_backoff_exponent: float

The exponential backoff scaling between successive attempts to communicate with the RPC service.

retry_wait_seconds: float

The number of seconds to wait between successive attempts to communicate with the RPC service.

rpc_init_max_seconds: float

The maximum number of seconds to wait for an RPC connection to establish.

rpc_max_retries: int

The maximum number of failed attempts to communicate with the RPC service before raising an error. Retries are made only for communication errors. Failures from other causes such as error signals raised by the service are not retried.

script_args: List[str]

If the service is started from a local script, this set of args is used on the command line. No effect when used for existing sockets.

script_env: Dict[str, str]

If the service is started from a local script, this set of env vars is used on the command line. No effect when used for existing sockets.

Exceptions

In general, errors raised by the service are converted to the equivalent builtin exception type, e.g., ValueError for invalid method arguments, and FileNotFound for resource errors. However, some error cases are not well covered by the builtin exception hierarchy. For those cases, we define custom exception types, all inheriting from a base ServiceError class:

exception compiler_gym.service.ServiceError[source]

Error raised from the service.

exception compiler_gym.service.EnvironmentNotSupported[source]

Error raised if the runtime requirements for an environment are not met on the current system.

exception compiler_gym.service.ServiceInitError[source]

Error raised if the service fails to initialize.

exception compiler_gym.service.ServiceTransportError[source]

Error that is raised if communication with the service fails.

exception compiler_gym.service.ServiceIsClosed[source]

Error that is raised if trying to interact with a closed service.

exception compiler_gym.service.SessionNotFound[source]

Requested session ID not found in service.