Search Strategy#
CompileIQ searches a large configuration space by evaluating batches of candidate
parameter sets, keeping the most useful signal from each batch, and using that
signal to choose the next batch. You usually only need to provide an objective
function, a search space, and a SearchConfiguration.
Core Concepts#
A
search spacedescribes the parameters CompileIQ may vary.A
candidateis one sampled parameter set from that space.A
poolis the batch of candidates evaluated in one iteration.A
generationis one search iteration.mutate_ratecontrols how aggressively later candidates explore new values.
For example, two parameters with ranges from 1 to 100 and step size 1 create 10,000 possible candidates. CompileIQ samples and evaluates a manageable subset instead of requiring you to search that space manually.
How a Search Progresses#
CompileIQ samples an initial pool of candidates.
Workers evaluate each candidate by calling your objective function.
Scores are returned to the core over local socket IPC.
The core uses the scores to choose another pool of candidates.
The process repeats until the configured number of generations completes.
Larger pool_size values give CompileIQ more candidates to compare per
generation. Larger generations values give it more rounds to refine the
search. For expensive compiler workloads, start small and scale only after your
objective function, correctness checks, and timeout behavior are reliable.
Exploration And Refinement#
CompileIQ balances two needs:
Explore enough of the search space to avoid getting stuck on an early result.
Refine promising regions so the final candidates are useful.
mutate_rate, pool_size, cull_size, and init_with_true_random_threshold
control this balance. The defaults are intended to be usable for common cases,
but large or failure-heavy search spaces may need larger pools, more generations,
or objective-side guardrails that mark bad candidates as INVALID_SCORE.
Practical Guidance#
Use Search.sample(...) before a full run to inspect candidate shapes and catch
objective-function assumptions early. This is especially useful for nested search
spaces and searches that combine application parameters with compiler controls,
where the objective function needs to handle a specific input shape.
Think about pool_size as the amount of evidence CompileIQ gathers in each
generation. A larger pool gives the core more candidates to compare before it
chooses the next direction. Small pools are useful for smoke tests and expensive
workloads, but they can miss useful regions of a large search space. When the
objective is stable and affordable, increasing pool_size is often the first
way to make a search more robust.
Think about generations as the number of opportunities CompileIQ has to react
to measurements. More generations let the search refine promising regions over
time, but they also multiply the total number of objective evaluations. Start
with a short run to validate correctness, then scale the run once the objective
function, cache behavior, and timeout handling are reliable.
cull_size controls how much of the current pool is used as signal for later
generations. Smaller values focus the search more aggressively around the best
observed candidates. Larger values preserve more variety, which can help when
the score is noisy or when many candidates fail for reasons unrelated to
performance.
mutate_rate controls how often later candidates are perturbed away from the
regions that already look promising. Too little mutation can leave the search
stuck around an early result. Too much mutation can make the search keep
exploring after it has enough signal to refine useful candidates.
If later candidates appear less varied than the initial pool, the search may be
spending more effort near regions that have already scored well. If the best
score stops improving, the failure rate rises, or every sampled candidate looks
similar too early, consider increasing pool_size, running more generations, or
adjusting mutate_rate.
When tuning compiler controls, always add correctness checks, compile/runtime timeouts, and repeatable benchmarking before trusting a candidate. A fast but incorrect candidate is still a failed candidate.