Compile options
Every program a Nitro handle compiles goes through Reactant.Compiler.compile, the call behind @compile. The compile_options keyword passes Reactant's compile keywords to all of them, so anything you would write as @compile raise = true f(x) is set once, on the handle.
nitro = Nitro(e; compile_options = (; raise = true))train!(nitro)Two forms
A NamedTuple of the keywords Reactant.Compiler.compile takes:
Nitro(e; compile_options = (; raise = true, cudnn_hlo_optimize = true, transpose_propagate = :down))Nitro(e; compile_options = (; xla_debug_options = (; xla_gpu_exhaustive_tiling_search = true)))A Reactant.CompileOptions, for the pass switches that are fields of CompileOptions but not compile keywords:
Nitro(e; compile_options = Reactant.CompileOptions(; raise = true, disable_slice_to_batch_passes = false))The two combine: a NamedTuple may carry a CompileOptions under its own compile_options key.
Which keywords exist
The accepted set is read from your installed Reactant, not hard-coded, so a keyword added upstream works with no change here. Commonly useful ones:
| Keyword | Effect |
|---|---|
raise | true runs Reactant's raising pipeline, which lowers custom kernels (CUDA, KernelAbstractions) to StableHLO; a String is a custom raising pass pipeline |
raise_first | raise before the main optimization passes rather than after |
optimize | false skips the optimization passes, or a Symbol/String picks a pipeline |
cudnn_hlo_optimize | enables the cuDNN HLO rewrites |
transpose_propagate, reshape_propagate | :up (the default), :down or :none |
no_nan, all_finite | let the optimizer assume finite values |
xla_debug_options | XLA debug flags, as a NamedTuple |
Reactant forces raise = true on TPU and for sharded programs, so setting it there has no effect.
XLA options
Three keywords set fields of XLA's own protos, which XLA documents:
| Keyword | XLA proto | Reference |
|---|---|---|
xla_debug_options | DebugOptions | xla.proto, flag guidance |
xla_executable_build_options | ExecutableBuildOptionsProto | compile_options.proto, effort levels |
xla_compile_options | CompileOptionsProto | compile_options.proto |
Autotuning
GPU autotuning is set through DebugOptions:
Nitro(e; compile_options = (; xla_debug_options = (; xla_gpu_autotune_level = 0, # no GEMM/convolution autotuning: faster compiles xla_gpu_exhaustive_tiling_search = true, # autotune every block-level fusion: slower compiles)))XLA's overall compile effort is a separate setting, on ExecutableBuildOptionsProto:
const Effort = Reactant.Proto.xla.var"ExecutionOptions.EffortLevel"Nitro(e; compile_options = (; xla_executable_build_options = (; optimization_level = Effort.EFFORT_O3)))Reactant keeps a persisted autotune cache when its persistent compile cache is on, and a fusion found there is not autotuned again. To compare autotuning settings, clear it first with Reactant.PersistentCompileCache.clear_compilation_cache!().
Validation
Nitro checks the options before the setup sequence runs, so a mistake fails at once instead of at the first compile:
- an unknown keyword is refused, and the error lists the accepted ones
- a
CompileOptionsfield passed as a keyword is refused, with a pointer to theCompileOptionsform - an unknown field of
xla_debug_options,xla_executable_build_optionsorxla_compile_optionsis refused donated_argsother than:autois refused: the parameters and the gradient accumulator are updated in place, and without donation every superseded buffer waits for the GC
See ReactantNitro.check_compile_options.
Recompilation
The options are part of each program's compile-cache key (see Recompilation). A handle with raise = true and one without get separate programs, and the default programs stay cached alongside them. An empty compile_options leaves the key exactly as it was.
Scope and limits
The options apply to every program the handle compiles: the gradient, optimizer, evaluation and metric programs. There is no per-phase setting.
They do not reach: