Skip to content

Adjust loop unrolling defaults#1584

Merged
sim642 merged 5 commits intomasterfrom
loopUnroll-default
Oct 2, 2024
Merged

Adjust loop unrolling defaults#1584
sim642 merged 5 commits intomasterfrom
loopUnroll-default

Conversation

@karoliineh
Copy link
Copy Markdown
Member

The manual inspection of not enabling vs enabling loopUnrolling showed that the stats for the current unrolling are (broadly) the following:

  • The maximum of loop unrolling is 25
  • The average of loop unrolling is 6
  • The median of loop unrolling is 4

Looking into the semantics of the tasks where unrolling helped us verify (Unknown -> True), however, revealed that

  • The maximum bound of (other than nondet) is 1000000
  • The average bound is 37074
  • The median bound is 10

Regardless of the semantics of the program, I also tried to find the minimum amount of unrollings necessary for solving the task. This showed that:

  • The average minimum unrollings needed to solve the task is 2
  • The median minimum is 10

For all loops with a nondet bound that I found by inspection, the sufficient (minimum) times of unrollings needed for solving the task is at max 2.

As revealed by some intermediate runs, unrolling fixed loops with the bound up to 100 makes us timeout in many of the instances (including on some of the regression tests; see #1516 (comment)). For the maximum bound of loop unrolling, which was 25 previously, the actual semantics were that the loop has to be unrolled by a minimum of 19 times (the syntax can determine that) for us to solve the task. Thus, I have changed the heuristic of if totalLoops < 17 && AutoTune0.isActivated "forceLoopUnrollForFewLoops" then 10 else 0 in to | Some i when i <= 20 -> i, i.e., if a fixed loop iteration of 20 or less is found, we will unroll the loop the found amount of times.
(The next old unroll maximum would be 16, where the semantics is nondet, and 1 unroll is sufficient, and further from that, the new max is 12, which cases semantics I have not looked into too thoroughly yet.)

Otherwise, if the found loop iterations are 20+, we will default to the median of the previous unrolling (4), which, in many cases, is the sufficient amount of unrolling needed to solve a task - so, we would default to unrolling 4 times instead of the complicated heuristic of calculating some (weird) bound based on the number of statements in the loop: max unroll_min (targetInstructions / loopStats.instructions). According to a run with these settings, we do not lose too many tasks but gain a bit in performance (e.g. instead of the "random" unrolling of 12 times in many cases, where 2 times would be sufficient, we now only unroll 4 times).

We made a run with these new defaults, and I investigated some of the tasks (edge cases) where we could not solve the task because the iterations found by the new heuristics were too small. Some PRs will follow this PR to again handle these lost cases in addition to some new tasks that we can further solve due to some (new) improvements to the unrolling.

@karoliineh karoliineh added sv-comp SV-COMP (analyses, results), witnesses performance Analysis time, memory usage labels Sep 28, 2024
@karoliineh karoliineh added this to the SV-COMP 2025 milestone Sep 28, 2024
@karoliineh karoliineh self-assigned this Sep 28, 2024
@karoliineh
Copy link
Copy Markdown
Member Author

The regression fails here due to the thing described in #1583, so this PR actually needs the unrolling of the loops in the stub functions to be disabled.

@karoliineh karoliineh requested a review from sim642 October 2, 2024 12:38
@sim642 sim642 merged commit bb6f9aa into master Oct 2, 2024
@sim642 sim642 deleted the loopUnroll-default branch October 2, 2024 15:04
sim642 added a commit to sim642/opam-repository that referenced this pull request Nov 28, 2024
CHANGES:

Functionally equivalent to Goblint in SV-COMP 2025.

* Add 32bit vs 64bit architecture support (goblint/analyzer#54, goblint/analyzer#1574).
* Add per-function context gas analysis (goblint/analyzer#1569, goblint/analyzer#1570, goblint/analyzer#1598).
* Adapt automatic static loop unrolling (goblint/analyzer#1516, goblint/analyzer#1582, goblint/analyzer#1583, goblint/analyzer#1584, goblint/analyzer#1590, goblint/analyzer#1595, goblint/analyzer#1599).
* Adapt automatic configuration tuning (goblint/analyzer#1450, goblint/analyzer#1612, goblint/analyzer#1181, goblint/analyzer#1604).
* Simplify non-relational integer invariants in witnesses (goblint/analyzer#1517).
* Fix excessive hash collisions (goblint/analyzer#1594, goblint/analyzer#1602).
* Clean up various code (goblint/analyzer#1095, goblint/analyzer#1523, goblint/analyzer#1554, goblint/analyzer#1575, goblint/analyzer#1588, goblint/analyzer#1597, goblint/analyzer#1614).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Analysis time, memory usage precision sv-comp SV-COMP (analyses, results), witnesses

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants