Skip to content

Evolution Loop Profiling

Jgocunha edited this page Aug 31, 2026 · 1 revision

Evolution-loop profiling

Opt-in per-phase timing for Population::evolve(). Answers "which phase of a generation is slow" instead of only knowing total run duration.

Enable it

Build with the CMake cache option on:

cmake -B build -S neat-dnfs -DNEAT_DNFS_PROFILE=ON ...

Off by default. When off, the timer types compile to nothing — no storage, no locking, no clock reads, zero runtime cost.

What you get

Every evolution run writes profile.csv into the run's output directory (data/<solutionName>/<timestamp>/profile.csv), one row per generation:

generation,evaluate,speciate,upkeep,reproduceAndSelect,save
1,0.02196,2.78e-05,0.0261534,0.0003992,0.0251842
2,0.0252292,8.9e-06,0.0262199,0.0004335,0.0252712
3,0.0267178,8.7e-06,0.0258752,0.0004648,0.0249319

Values are seconds. Columns:

Column What it times
evaluate Running every genome's phenotype (parallelized internally)
speciate Grouping genomes into species
upkeep Bookkeeping + file I/O for the generation
reproduceAndSelect Selection, crossover, mutation for the next generation
save The file-I/O part of upkeep — timed separately for visibility

upkeep includes save, it does not sit beside it. Columns do not sum to the generation total; treat save as a breakdown of upkeep, not a sixth phase.

Using it to optimize

  1. Run a representative evolution with -DNEAT_DNFS_PROFILE=ON.
  2. Open profile.csv and look at which column dominates the row.
    • evaluate dominating → the bottleneck is genome/phenotype simulation cost, or population size. Look at the task's DNF simulation, not the NEAT machinery.
    • save dominating → file-I/O settings are the cost, not evolution itself. Check config/neat_dnfs.json's saveXxx flags — turning off ones you don't need (e.g. saveSolutions) scales down with population size.
    • speciate or reproduceAndSelect dominating → look at genome/species count and the NEAT operators themselves; this is unusual unless population size is large.
  3. Compare columns across generations, not just within one row — a phase that grows with generation number points at something accumulating (e.g. species count, genome size) rather than a fixed per-call cost.
  4. Re-run after a change and diff the new profile.csv against the old one to confirm the fix actually moved the number you targeted.

Notes

  • Only the main thread records. evaluate()'s parallel std::async workers are deliberately uninstrumented, so this is safe under -DNEAT_DNFS_SANITIZER=thread.
  • Columns are a fixed, explicit set. A phase that didn't run in a given generation reports 0.0 rather than shifting later columns — rows always align with the header.

Clone this wiki locally