Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: visit less clauses during propagation #66

Conversation

baszalmstra
Copy link
Contributor

@baszalmstra baszalmstra commented Sep 26, 2024

This branch adds several optimizations. From large impact to small they are:

  • We implement two watch literals by monitoring literals now instead of solvables. This removes a lot of unnecessary work.
  • It refrains from adding forbidden clauses for packages that will never be selected anyway. This reduces the number of clauses and thus improving backtracking performance.
  • We also reduced the memory size of clauses from 24 to 16 bytes per clause, improving cache locality.
  • Furthermore we investigated forcibly inlining certain code paths which also showed a small performance improvement.

@wolfv
Copy link
Member

wolfv commented Sep 27, 2024

Two flamegraphs, before and after. The timing difference is huge - after this PR it finishes in a second or so, and before it took more than 30 secs before I killed it.

after flamegraph

before flamegraph

@baszalmstra
Copy link
Contributor Author

Here are the benchmark results compared to the main branch:

Untitled
Untitled

This is a clear improvement.

@jjerphan You might be interested in this one!

@baszalmstra baszalmstra marked this pull request as ready for review September 27, 2024 17:11
@wolfv wolfv changed the title perf: only add forbidden clauses for visisted solvables perf: only add forbidden clauses for visited solvables Sep 27, 2024
@baszalmstra baszalmstra changed the title perf: only add forbidden clauses for visited solvables perf: visit less clauses during propagation Sep 28, 2024
@jjerphan
Copy link
Member

Hi @baszalmstra and @wolfv,

At first sight, the performance improvements are quite significant.

I am definitely interested in having a look at this and at other ones. I need to find some proper time to review it.

On a side note, I would like to implement an ILP formulation of the problem (as first highlighted by @DerThorsten): this offers theoretical consistency but might not offer tractability in practice. I wrote a few notes about it.

@baszalmstra baszalmstra force-pushed the performance/only_add_forbidden_for_visisted_solvables branch from ba5b415 to 838bf88 Compare September 30, 2024 08:19
/// Constructs a new [`Literal`] from a [`InternalSolvableId`] and a boolean
/// indicating whether the literal should be negated.
pub fn new(solvable_id: InternalSolvableId, negate: bool) -> Self {
assert!(solvable_id.0 < (u32::MAX >> 1) - 1, "solvable id too big");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could / should this be a debug assert? I assume we're not constructing so many literals on the fly anymore, so perhaps this is fine?

@@ -1078,41 +1126,43 @@ impl<D: DependencyProvider, RT: AsyncRuntime> Solver<D, RT> {
) -> Result<u32, Conflict> {
{
tracing::info!(
"├ Propagation conflicted: could not set {solvable} to {attempted_value}",
"├ Propagation conflicted: could not set {solvable} to {attempted_value}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is such beautiful ascii pipes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants