compiler_gym.envs

The CompilerEnv environment is a drop-in replacement for the basic gym.Env class, with extended functionality for compilers. Some compiler services may further extend the functionality by subclassing from CompilerEnv. The following environment classes are available:

Environment Classes:

CompilerEnv

class compiler_gym.envs.CompilerEnv(service: Union[str, pathlib.Path], rewards: Optional[List[compiler_gym.spaces.reward.Reward]] = None, datasets: Optional[Iterable[compiler_gym.datasets.dataset.Dataset]] = None, benchmark: Optional[Union[str, compiler_gym.datasets.benchmark.Benchmark]] = None, observation_space: Optional[Union[str, compiler_gym.views.observation_space_spec.ObservationSpaceSpec]] = None, reward_space: Optional[Union[str, compiler_gym.spaces.reward.Reward]] = None, action_space: Optional[str] = None, connection_settings: Optional[compiler_gym.service.connection.ConnectionOpts] = None, service_connection: Optional[compiler_gym.service.connection.CompilerGymServiceConnection] = None, logger: Optional[logging.Logger] = None)[source]

An OpenAI gym environment for compiler optimizations.

The easiest way to create a CompilerGym environment is to call gym.make() on one of the registered environments:

>>> env = gym.make("llvm-v0")

See compiler_gym.COMPILER_GYM_ENVS for a list of registered environment names.

Alternatively, an environment can be constructed directly, such as by connecting to a running compiler service at localhost:8080 (see this document for more details):

>>> env = CompilerEnv(
...     service="localhost:8080",
...     observation_space="features",
...     reward_space="runtime",
...     rewards=[env_reward_spaces],
... )

Once constructed, an environment can be used in exactly the same way as a regular gym.Env, e.g.

>>> observation = env.reset()
>>> cumulative_reward = 0
>>> for i in range(100):
>>>     action = env.action_space.sample()
>>>     observation, reward, done, info = env.step(action)
>>>     cumulative_reward += reward
>>>     if done:
>>>         break
>>> print(f"Reward after {i} steps: {cumulative_reward}")
Reward after 100 steps: -0.32123
Variables
  • service (compiler_gym.service.CompilerGymServiceConnection) – A connection to the underlying compiler service.

  • logger (logging.Logger) – A Logger instance used by the environment for communicating info and warnings.

  • action_spaces (List[str]) – A list of supported action space names.

  • actions (List[int]) – The list of actions that have been performed since the previous call to reset().

  • reward_range (Tuple[float, float]) – A tuple indicating the range of reward values. Default range is (-inf, +inf).

  • observation (compiler_gym.views.ObservationView) – A view of the available observation spaces that permits on-demand computation of observations.

  • reward (compiler_gym.views.RewardView) – A view of the available reward spaces that permits on-demand computation of rewards.

  • episode_reward (float) – If CompilerEnv.reward_space is set, this value is the sum of all rewards for the current episode.

__init__(service: Union[str, pathlib.Path], rewards: Optional[List[compiler_gym.spaces.reward.Reward]] = None, datasets: Optional[Iterable[compiler_gym.datasets.dataset.Dataset]] = None, benchmark: Optional[Union[str, compiler_gym.datasets.benchmark.Benchmark]] = None, observation_space: Optional[Union[str, compiler_gym.views.observation_space_spec.ObservationSpaceSpec]] = None, reward_space: Optional[Union[str, compiler_gym.spaces.reward.Reward]] = None, action_space: Optional[str] = None, connection_settings: Optional[compiler_gym.service.connection.ConnectionOpts] = None, service_connection: Optional[compiler_gym.service.connection.CompilerGymServiceConnection] = None, logger: Optional[logging.Logger] = None)[source]

Construct and initialize a CompilerGym service 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.

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

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

  • logger – The logger to use for this environment. If not provided, a compiler_gym.envs logger is used and assigned the verbosity returned by get_logging_level().

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: compiler_gym.spaces.named_discrete.NamedDiscrete

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.

apply(state: compiler_gym.compiler_env_state.CompilerEnvState)None[source]

Replay this state on the given an environment.

Parameters

env – A CompilerEnv instance.

Raises

ValueError – If this state cannot be applied.

property available_datasets: Dict[str, compiler_gym.datasets.dataset.Dataset]

A dictionary of datasets.

Deprecated since version 0.1.8: Use env.datasets.datasets() instead. More information.

property benchmark: compiler_gym.datasets.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.

property benchmarks: Iterable[str]

Enumerate a (possible unbounded) list of available benchmarks.

Deprecated since version 0.1.8: Use env.datasets.benchmarks() instead. More information.

close()[source]

Close the environment.

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

Note

Internally, CompilerGym environments may launch subprocesses and use temporary files to communicate between the environment and the underlying compiler (see compiler_gym.service for details). This means it is important to call env.close() after use to free up resources and prevent orphan subprocesses or files. We recommend using the with-statement pattern for creating environments:

>>> with gym.make("llvm-autophase-ic-v0") as env:
...    env.reset()
...    # use env how you like

This removes the need to call env.close() yourself.

commandline()str[source]

Interface for CompilerEnv subclasses to provide an equivalent commandline invocation to the current environment state.

See also commandline_to_actions().

Calling this method on a CompilerEnv instance raises NotImplementedError.

Returns

A string commandline invocation.

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

Interface for CompilerEnv subclasses to convert from a commandline invocation to a sequence of actions.

See also commandline().

Calling this method on a CompilerEnv instance raises NotImplementedError.

Returns

A list of actions.

property compiler_version: str

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

property episode_walltime: float

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

fork()compiler_gym.envs.compiler_env.CompilerEnv[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
Returns

A new environment instance.

get_benchmark_validation_callback()Optional[Callable[[compiler_gym.envs.compiler_env.CompilerEnv], Iterable[compiler_gym.validation_error.ValidationError]]][source]

Return a callback that validates benchmark semantics, if available.

Deprecated since version 0.1.8: Use env.validate() instead. More information.

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.

property observation_space: Optional[gym.spaces.space.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[int], observations: Iterable[compiler_gym.views.observation_space_spec.ObservationSpaceSpec], rewards: Iterable[compiler_gym.spaces.reward.Reward])Tuple[Optional[Union[compiler_gym.util.gym_type_hints.ObservationType, List[compiler_gym.util.gym_type_hints.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

Prefer step() to raw_step(). step() has equivalent functionality, and is less likely to change in the future.

register_dataset(dataset: compiler_gym.datasets.dataset.Dataset)bool[source]

Register a new dataset.

Example usage:

>>> my_dataset = Dataset(name="my-dataset-v0", ...)
>>> env = gym.make("llvm-v0")
>>> env.register_dataset(my_dataset)
>>> env.benchmark = "my-dataset-v0/1"
param dataset

A Dataset instance describing the new dataset.

return

True if the dataset was added, else False.

raises ValueError

If a dataset with this name is already registered.

Deprecated since version 0.1.8: Use env.datasets.add() instead. More information.

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

Render the environment.

CompilerEnv 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.

require_dataset(dataset: Union[str, compiler_gym.datasets.dataset.Dataset])bool[source]

Deprecated function for managing datasets.

Datasets are now installed automatically. See env.datasets.

param dataset

The name of the dataset to download, the URL of the dataset, or a Dataset instance.

return

True if the dataset was downloaded, or False if the dataset was already available.

Deprecated since version 0.1.8: Use env.datasets.require() instead. More information.

require_datasets(datasets: List[Union[str, compiler_gym.datasets.dataset.Dataset]])bool[source]

Deprecated function for managing datasets.

Datasets are now installed automatically. See env.datasets.

param datasets

A list of datasets to require. Each dataset is the name of an available dataset, the URL of a dataset to download, or a Dataset instance.

return

True if one or more datasets were downloaded, or False if all datasets were already available.

Deprecated since version 0.1.8: Datasets are now installed automatically, there is no need to call require(). More information.

reset(benchmark: Optional[Union[str, compiler_gym.datasets.benchmark.Benchmark]] = None, action_space: Optional[str] = None, retry_count: int = 0)Optional[compiler_gym.util.gym_type_hints.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.

Returns

The initial observation.

Raises
  • BenchmarkInitError – If the benchmark is invalid. 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_space: Optional[compiler_gym.spaces.reward.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)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.

Returns

The response from the compiler service.

Raises

SessionNotFound – If called before reset().

send_params(*params: Iterable[Tuple[str, str]])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.

Returns

A list of string responses, one per parameter.

Raises

SessionNotFound – If called before reset().

property state: compiler_gym.compiler_env_state.CompilerEnvState

The tuple representation of the current environment state.

step(action: Union[int, Iterable[int]], observations: Optional[Iterable[Union[str, compiler_gym.views.observation_space_spec.ObservationSpaceSpec]]] = None, rewards: Optional[Iterable[Union[str, compiler_gym.spaces.reward.Reward]]] = None)Tuple[Optional[Union[compiler_gym.util.gym_type_hints.ObservationType, List[compiler_gym.util.gym_type_hints.ObservationType]]], Optional[Union[float, List[float]]], bool, Dict[str, Any]][source]

Take a step.

Parameters
  • action – An action, or a sequence of actions. When multiple actions are provided the observation and reward are returned after running all of the actions.

  • observations – A list of observation spaces to compute observations from. If provided, this changes the observation element of the return tuple to be a list of observations from the requested spaces. The default env.observation_space is not returned.

  • rewards – A list of reward spaces to compute rewards from. If provided, this changes the reward element of the return tuple to be a list of rewards from the requested spaces. The default env.reward_space is not returned.

Returns

A tuple of observation, reward, done, and info. Observation and reward are None if default observation/reward is not set.

Raises

SessionNotFound – If reset() has not been called.

validate(state: Optional[compiler_gym.compiler_env_state.CompilerEnvState] = None)compiler_gym.validation_result.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: compiler_gym.service.proto.compiler_gym_service_pb2.GetVersionReply

Get the version numbers from the compiler service.

LlvmEnv

class compiler_gym.envs.LlvmEnv(*args, benchmark: Optional[Union[str, compiler_gym.datasets.benchmark.Benchmark]] = None, datasets_site_path: Optional[pathlib.Path] = None, **kwargs)[source]

A specialized CompilerEnv for LLVM.

This extends the default CompilerEnv environment, adding extra LLVM functionality. Specifically, the actions use the CommandlineFlag space, which is a type of Discrete space that provides additional documentation about each action, and the LlvmEnv.commandline() method can be used to produce an equivalent LLVM opt invocation for the current environment state.

commandline(textformat: bool = False)str[source]

Returns an LLVM opt command line invocation for the current environment state.

Parameters

textformat – Whether to generate a command line that processes text-format LLVM-IR or bitcode (the default).

Returns

A command line string.

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

Returns a list of actions from the given command line.

Parameters

commandline – A command line invocation, as generated by env.commandline().

Returns

A list of actions.

Raises

ValueError – In case the command line string is malformed.

property ir: str

Print the LLVM-IR of the program in its current state.

Alias for env.observation["Ir"].

Returns

A string of LLVM-IR.

property ir_sha1: str

Return the 40-characeter hex sha1 checksum of the current IR.

Equivalent to: hashlib.sha1(env.ir.encode("utf-8")).hexdigest().

Returns

A 40-character hexadecimal sha1 string.

make_benchmark(inputs: Union[str, pathlib.Path, compiler_gym.envs.llvm.llvm_benchmark.ClangInvocation, List[Union[str, pathlib.Path, compiler_gym.envs.llvm.llvm_benchmark.ClangInvocation]]], copt: Optional[List[str]] = None, system_includes: bool = True, timeout: int = 600)compiler_gym.datasets.benchmark.Benchmark[source]

Create a benchmark for use with this environment.

This function takes one or more inputs and uses them to create a benchmark that can be passed to compiler_gym.envs.LlvmEnv.reset().

For single-source C/C++ programs, you can pass the path of the source file:

>>> benchmark = make_benchmark('my_app.c')
>>> env = gym.make("llvm-v0")
>>> env.reset(benchmark=benchmark)

The clang invocation used is roughly equivalent to:

$ clang my_app.c -O0 -c -emit-llvm -o benchmark.bc

Additional compile-time arguments to clang can be provided using the copt argument:

>>> benchmark = make_benchmark('/path/to/my_app.cpp', copt=['-O2'])

If you need more fine-grained control over the options, you can directly construct a ClangInvocation to pass a list of arguments to clang:

>>> benchmark = make_benchmark(
    ClangInvocation(['/path/to/my_app.c'], timeout=10)
)

For multi-file programs, pass a list of inputs that will be compiled separately and then linked to a single module:

>>> benchmark = make_benchmark([
    'main.c',
    'lib.cpp',
    'lib2.bc',
])

If you already have prepared bitcode files, those can be linked and used directly:

>>> benchmark = make_benchmark([
    'bitcode1.bc',
    'bitcode2.bc',
])

Note

LLVM bitcode compatibility is not guaranteed, so you must ensure that any precompiled bitcodes are compatible with the LLVM version used by CompilerGym, which can be queried using LlvmEnv.compiler_version.

Parameters
  • inputs – An input, or list of inputs.

  • copt – A list of command line options to pass to clang when compiling source files.

  • system_includes – Whether to include the system standard libraries during compilation jobs. This requires a system toolchain. See get_system_includes().

  • timeout – The maximum number of seconds to allow clang to run before terminating.

Returns

A Benchmark instance.

Raises
  • FileNotFoundError – If any input sources are not found.

  • TypeError – If the inputs are of unsupported types.

  • OSError – If a compilation job fails.

  • TimeoutExpired – If a compilation job exceeds timeout seconds.

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

Render the environment.

CompilerEnv 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(*args, **kwargs)[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.

Returns

The initial observation.

Raises
  • BenchmarkInitError – If the benchmark is invalid. 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 runtime_observation_count: int

The number of runtimes to return for the Runtime observation space.

See the Runtime observation space reference for further details.

Example usage:

>>> env = compiler_gym.make("llvm-v0")
>>> env.reset()
>>> env.runtime_observation_count = 10
>>> len(env.observation.Runtime())
10
Getter

Returns the number of runtimes that will be returned when a Runtime observation is requested.

Setter

Set the number of runtimes to compute when a Runtime observation is requested.

Type

int

property runtime_warmup_runs_count: int

The number of warmup runs of the binary to perform before measuring the Runtime observation space.

See the Runtime observation space reference for further details.

Example usage:

>>> env = compiler_gym.make("llvm-v0")
>>> env.reset()
>>> env.runtime_observation_count = 10
>>> len(env.observation.Runtime())
10
Getter

Returns the number of runs that be performed before measuring the Runtime observation is requested.

Setter

Set the number of warmup runs to perform when a Runtime observation is requested.

Type

int

write_bitcode(path: Union[pathlib.Path, str])pathlib.Path[source]

Write the current program state to a bitcode file.

Parameters

path – The path of the file to write.

Returns

The input path argument.

write_ir(path: Union[pathlib.Path, str])pathlib.Path[source]

Write the current program state to a file.

Parameters

path – The path of the file to write.

Returns

The input path argument.

GccEnv

class compiler_gym.envs.GccEnv(*args, gcc_bin: Union[str, pathlib.Path] = 'docker:gcc:11.2.0', benchmark: Union[str, compiler_gym.datasets.benchmark.Benchmark] = 'benchmark://chstone-v0/adpcm', datasets_site_path: Optional[pathlib.Path] = None, connection_settings: Optional[compiler_gym.service.connection.ConnectionOpts] = None, timeout: Optional[int] = None, **kwargs)[source]

A specialized CompilerEnv for GCC.

This class exposes the optimization space of GCC’s command line flags as an environment for reinforcement learning. For further details, see the GCC Environment Reference.

property asm: str

Get the assembly code.

property asm_hash: str

Get a hash of the assembly code.

property asm_size: int

Get the assembly code size in bytes.

property choices: List[int]

Get the current choices

commandline()str[source]

Return a string representing the command line options.

Returns

A string.

property gcc_spec: compiler_gym.envs.gcc.gcc.GccSpec

A GccSpec description of the compiler specification.

property instruction_counts: Dict[str, int]

Get a count of the instruction types in the assembly code.

Note, that it will also count fields beginning with a ., like .bss and .align. Make sure to remove those if not needed.

property obj: bytes

Get the object code.

property obj_hash: str

Get a hash of the object code.

property obj_size: int

Get the object code size in bytes.

reset(benchmark: Optional[Union[str, compiler_gym.datasets.benchmark.Benchmark]] = None, action_space: Optional[str] = None, retry_count: int = 0)Optional[compiler_gym.util.gym_type_hints.ObservationType][source]

Reset the environment. This additionally sets the timeout to the correct value.

property rtl: str

Get the final rtl of the program.

property source: str

Get the source code.

property timeout: Optional[int]

Get the current compilation timeout