110 lines
5.9 KiB
Markdown
110 lines
5.9 KiB
Markdown
# Solver optimization audit
|
|
|
|
Measured on an Intel Core i5-12600K, Linux, GCC 16.2.1, Release (`-O3`,
|
|
no fast-math). Reference is commit `589d22a`. Performance results are specific
|
|
to this machine; Windows/MSVC runtime measurements remain pending. The retained
|
|
changes use portable C++ and compiler vectorization, with no new CPU requirement.
|
|
|
|
## Retained changes
|
|
|
|
* Boundary solves start from the previous converged face pressure when it is
|
|
inside the new physical bracket. Otherwise they start at the bracket midpoint.
|
|
The safeguarded Newton solver, residual tolerance, iteration cap, choking,
|
|
reverse flow, donor budgets and inertance calculation remain unchanged.
|
|
* Pipe preparation computes primitive states and wave speeds in an independent
|
|
loop, then validates states and reduces the CFL timestep. GCC confirms 128-bit
|
|
vectorization of the arithmetic loop. Invalid states still throw before flux
|
|
updates. No approximate reciprocal/square root or relaxed arithmetic is used.
|
|
* Pipe fresh-air tracer fractions smaller than the smallest **normal** float
|
|
(approximately 1.175e-38) are rounded to zero. Previously, purged intake/exhaust
|
|
tracer tails persisted as subnormals, causing severe sustained-load slowdown.
|
|
This affects species attribution below that precision, not total density,
|
|
momentum or energy. The regression suite checks bulk conservation and retention
|
|
of normal tracer concentrations. Global flush-to-zero modes are not enabled.
|
|
|
|
Starting guesses change numerical trajectories within the existing convergence
|
|
tolerance; long engine/audio traces need not be bit-identical to the reference.
|
|
|
|
## Profiling and experiments
|
|
|
|
A `-pg` build running every scenario for two simulated seconds attributed about
|
|
39% of sampled executable time to pipe advancement, 38% to orifice boundary
|
|
solves, and 13% to Solver::step (including inlined preparation). Turbo mechanics
|
|
were under 1% and outdoor emitter rendering about 1%. These are sampled gprof
|
|
results, not precise attribution of time inside dynamically linked math functions.
|
|
|
|
`fluidsim_thread_benchmark` now uses each scenario's actual pipe geometry and
|
|
compares persistent 1/2/4-worker execution with barriers per substep. This isolates
|
|
the parallelizable pipe work; boundary/component work would remain serial. Every
|
|
current scenario loses with workers, so production remains serial. The synthetic
|
|
64-pipe, 256-cells-per-pipe case benefits from workers, confirming that this
|
|
strategy has a useful scale threshold. It does not justify adding its scheduling
|
|
and synchronization cost to the current small graphs.
|
|
|
|
SIMD-disabled and `-march=native` builds are comparison experiments. Native
|
|
compilation is not enabled in the project defaults, since the executable could
|
|
then require instructions missing on another machine.
|
|
|
|
## Results
|
|
|
|
Mean wall seconds per simulated second, six-second sustained-load runs:
|
|
|
|
| Scenario | Reference | Optimized | Time reduction | SIMD disabled |
|
|
|---|---:|---:|---:|---:|
|
|
| Twin | .528 | .405 | 23% | .423 |
|
|
| Turbo twin | 1.368 | .649 | 53% | .684 |
|
|
| B205 | .884 | .689 | 22% | .737 |
|
|
| Two-stroke racing | .561 | .470 | 16% | .535 |
|
|
| Two-stroke straight | .539 | .464 | 14% | .525 |
|
|
| Helmholtz | .167 | .141 | 16% | .160 |
|
|
| Pulse | .256 | .238 | 7% | .315 |
|
|
|
|
Idle/transient optimized means (seconds per simulated second): twin .394/.399,
|
|
turbo .627/.651, B205 .666/.683, racing two-stroke .450/.459, straight two-stroke
|
|
.452/.453, Helmholtz .141/.140, and pulse .238/.238.
|
|
|
|
The pulse scenario has no orifice, so its improvement isolates the SIMD-friendly
|
|
preparation change. Disabling SIMD increases time in every scenario. An optional
|
|
native-instruction build improves some timings further, but is not shipped as
|
|
the default: FMA also changes rounding and the binary is CPU-specific.
|
|
|
|
Initial isolated changes measured approximately .40 seconds for the twin after
|
|
boundary warm starts alone (previously .53). The sustained turbo still took
|
|
about 1.2 seconds after that change; eliminating subnormal tracer tails brought
|
|
it to about .65. The diagnostic found 22 subnormal pipe fields before truncation
|
|
and zero afterwards. This is distinct from reducing CFL substeps or geometry;
|
|
neither was changed. Six-second idle and throttle/release runs also complete
|
|
for every scenario. These are finite test windows, not a guarantee of real-time
|
|
performance for every user configuration or arbitrarily long simulation.
|
|
|
|
## Reproduction
|
|
|
|
Final validation: all nine CTest suites passed both with SIMD enabled (28.50 s)
|
|
and disabled (30.86 s). The fluid validation executable includes 30 checks,
|
|
including tracer underflow conservation. The Release SFML desktop target also
|
|
rebuilt successfully. This audit verifies desktop compilation and headless audio
|
|
rendering; interactive playback underrun testing remains a separate user check.
|
|
|
|
```sh
|
|
cmake -S . -B build-opt -DCMAKE_BUILD_TYPE=Release -DFLUIDSIM_BUILD_DESKTOP=OFF
|
|
cmake --build build-opt -j
|
|
ctest --test-dir build-opt --output-on-failure
|
|
./build-opt/fluidsim_scenario_benchmark 6 loaded
|
|
./build-opt/fluidsim_scenario_benchmark 6 idle
|
|
./build-opt/fluidsim_scenario_benchmark 6 transient
|
|
./build-opt/fluidsim_thread_benchmark
|
|
```
|
|
|
|
The scenario benchmark runs twin, turbo twin, B205, racing and straight-pipe
|
|
two-strokes, Helmholtz and pulse scenarios, including their normal audio path.
|
|
`loaded` holds four-strokes at 7,000 RPM and two-strokes at 10,000 RPM using an
|
|
ideal speed-holding dyno; engine throttle is 70%. `idle` releases the pedal;
|
|
`transient` starts released, applies 70%, then releases for the last two seconds.
|
|
The optional final argument selects one scenario, e.g. `6 loaded turbo`.
|
|
CSV timing/checksum goes to stdout; subnormal and iteration diagnostics go to
|
|
stderr. Inspection happens outside the timed sample-processing loop.
|
|
|
|
Use `-DFLUIDSIM_ENABLE_SIMD=OFF` in a separate build for scalar comparisons.
|
|
Run timed experiments sequentially, without concurrent builds or simulations.
|
|
The raw final measurements are retained in `verification/optimization/`.
|