Perf: 2-3x faster solver, identical output - #17
Open
erelShtosselCEVA wants to merge 1 commit into
Open
erelShtosselCEVA wants to merge 1 commit into
erelShtosselCEVA wants to merge 1 commit into
Conversation
Removes per-candidate heap allocations from the DFS and replaces two read-hot associative containers with sorted vectors. Solver output is unchanged. Optimization done with Claude.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi @mmoffitt!
Thank you for the amazing work!
I've used Claude to optimize the code, resulting in about x2-3 faster
runtime without changing the results. I checked it on the benchmarks
published in this repo, and an internal benchmark of 40K examples.
Three changes to the solver's hot path. No algorithmic or behavioural
change: output is byte-identical on all 11
benchmarks/challenginginputs,
--validatepasses on all of them, and the test suite is green.1.
SectionandBufferData::overlapsbecome sorted vectorsSectionwasabsl::flat_hash_set<BufferIdx>andoverlapswasabsl::btree_set<Overlap>. Both are written once duringSweepand onlyever iterated afterwards, never queried.
UpdateSectionDatawalkssweep_result_.sections[s_idx]once per affected section per node, sohash-set iteration (which skips empty slots) shows up directly.
Sweepstill uses a hash set for the mutable active/alive sets and converts on
the way out.
Each ordered buffer pair is visited exactly once, so
overlapsneeds nodedup, only a sort at the end of
Sweepto preserve the order thebtree_set previously provided.
2. Persistent undo trails instead of per-candidate vectors
UpdateSectionDataandUpdateMinOffsetseach returned a freshlyallocated vector,
affected_sectionswas aflat_hash_setconstructedinside the offset loop, and
ComputeOrderingreturned a vector by value.All four were allocated for every candidate offset, including the large
majority rejected by
Check.They are now member trails: callers record
size()on entry and unwind tothat mark on exit.
affected_sectionsuses a generation-stamped vector(O(1) dedup, no hashing, no allocation).
orderingneeds one reusablevector per recursion depth because it is handed to the recursive call as
orig_ordering; this uses astd::dequeso references stay valid as thepool grows.
Measured with an
LD_PRELOADmalloc interposer onbenchmarks/challenging/A.1048576.csv: 15,662,633 -> 119,995 mallocs.3. Throttled deadline check
SearchSolutionscalledabsl::Now()on every node even whenparams_.timeoutisInfiniteDuration(the default). Now the clock isonly read when a finite timeout was requested, and then once per 1024
nodes.
cancelled_is loaded relaxed.Also adds a fast path to
Buffer::effective_sizeandCreatePointsforbuffers with no gaps, which avoids an allocation and a sort per
overlapping pair. This is a no-op on the shipped benchmarks (only 150-215
buffers each) but matters at larger buffer counts.
Results
Built with
-O2 -DNDEBUGon a single core, using the solver's ownreported elapsed time, summed over all 11
benchmarks/challenginginputsat
--capacity=1048576:Test change
tests/sweeper_test.cchad three.sectionsliterals written innon-ascending order (
{1, 0},{1, 3, 2},{3, 2}), which only comparedequal under unordered-set semantics. They are sorted to match the new
vector type.
P.S. the Python integration works locally, can you push it to PyPI with
Windows and Linux wheels?