forked from jwiesler/ips4o-verify
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updating the repository for the public version on github.
(squashed commit)
- Loading branch information
1 parent
d68fa2c
commit 4e58ad5
Showing
92 changed files
with
360,627 additions
and
3,214 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# No shebang! | ||
|
||
## Weigl's little helper to download SMT-solvers. | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
# This script is meant to be executed inside an Github Action to download the SMT-solver. | ||
# It uses the Github cli tool "gh", which allows an easy access to the releases of a | ||
# repository, and to download it artifacts. | ||
# | ||
# This script will always the latest uploaded artifact. | ||
# | ||
# | ||
# For performance, you should consider caching. This script skips downloading if files are present. | ||
|
||
|
||
## Github workflow commands | ||
# Please have a look at https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions | ||
# which explains a lot of workflow commands and special files in Github Actions. | ||
|
||
|
||
## TODO | ||
# It would be nice to convert it into a real! Github action, which can also exploit | ||
# the API library of Github. A manual/tutorial is here: | ||
# | ||
# https://docs.github.com/en/actions/creating-actions/developing-a-third-party-cli-action | ||
|
||
mkdir smt-solvers | ||
cd smt-solvers | ||
|
||
|
||
################################################# | ||
echo "::group::{install z3}" | ||
echo "Check for Z3, if present skip installation" | ||
|
||
if readlink -f */bin/z3; then | ||
echo "::notice::{Z3 found. Caching works! Skip installation}" | ||
else | ||
echo "Download Z3" | ||
wget 'https://github.com/Z3Prover/z3/releases/download/z3-4.12.2/z3-4.12.2-x64-glibc-2.31.zip' | ||
unzip -n z3*.zip | ||
rm z3-*.zip | ||
fi | ||
|
||
Z3=$(readlink -f */bin/z3) | ||
chmod u+x $Z3 | ||
echo "Z3 added to path: $Z3" | ||
echo $(dirname $Z3) >> $GITHUB_PATH | ||
|
||
echo "::endgroup::" | ||
################################################# | ||
|
||
################################################# | ||
echo "::group::{install cvc5}" | ||
if -f cvc5-Linux; then | ||
echo "::notice::{Z3 found. Caching works! Skip installation}" | ||
else | ||
echo "Install CVC5" | ||
gh release download --skip-existing -p 'cvc5-Linux' -R cvc5/cvc5 | ||
fi | ||
|
||
CVC5=$(readlink -f cvc5-Linux) | ||
echo "CVC5 installed and added to path: CVC5" | ||
chmod u+x $CVC5 | ||
echo $(dirname $CVC5) >> $GITHUB_PATH | ||
|
||
echo "::endgroup::" | ||
################################################# | ||
|
||
echo "::group::{check installation/versions}" | ||
$Z3 -version | ||
|
||
$CVC5 --version | ||
echo "::endgroup::" |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,45 @@ | ||
name: Broad Release Tests | ||
name: Proof Replay | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: ["main", "master"] | ||
schedule: | ||
- cron: '0 5 * * 1' # every monday morning | ||
on: [ push ] | ||
|
||
permissions: | ||
checks: write | ||
checks: write | ||
|
||
jobs: | ||
unit-tests: | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [macos-latest, ubuntu-latest, windows-latest] | ||
java: [8,11,17,21] | ||
continue-on-error: false | ||
runs-on: ${{ matrix.os }} | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up JDK ${{ matrix.java }} | ||
uses: actions/setup-java@v3 | ||
with: | ||
java-version: ${{ matrix.java }} | ||
distribution: 'corretto' | ||
compile_and_test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up JDK 21 | ||
uses: actions/setup-java@v3 | ||
with: | ||
java-version: 21 | ||
distribution: 'corretto' | ||
- name: Build with Gradle | ||
uses: gradle/gradle-build-action@v2.4.2 | ||
with: | ||
arguments: --continue assemble check | ||
|
||
- name: Build with Gradle | ||
uses: gradle/gradle-build-action@v2.4.2 | ||
with: | ||
arguments: --continue test | ||
replay-proofs: | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
# target: [ check-overflow-methods, check-overflow-constructors, check-methods, check-constructors ] | ||
# Reduce checks until overflow is fixed | ||
target: [ check-methods, check-constructors ] | ||
runs-on: ubuntu-latest | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
|
||
- name: Verify with KeY | ||
uses: gradle/gradle-build-action@v2.4.2 | ||
with: | ||
arguments: --continue checkAll | ||
|
||
|
||
- name: Upload test results | ||
uses: actions/upload-artifact@v3.1.1 | ||
if: success() || failure() | ||
with: | ||
name: test-results-${{ matrix.os }} | ||
path: | | ||
**/build/test-results/*/*.xml | ||
**/build/reports/ | ||
!**/jacocoTestReport.xml | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up JDK 21 | ||
uses: actions/setup-java@v3 | ||
with: | ||
java-version: 21 | ||
distribution: 'corretto' | ||
- name: Install SMT-Solvers | ||
run: .github/dlsmt.sh | ||
shell: bash | ||
- name: "Verify with KeY ${{ matrix.target }}" | ||
run: make ${{ matrix.target }} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
KEY_JAR=tools/key-2.11.0-exe.jar | ||
KEY_OVERFLOW_JAR=tools/key-2.11.0-o-exe.jar | ||
CI_TOOL=tools/citool-1.4.0-mini.jar | ||
|
||
checkCommand=java -Dlogback.configurationFile=./gradle/disablelogging.xml -Dkey.contractOrder="contract-order.txt" -cp "$(KEY_JAR):$(CI_TOOL)" de.uka.ilkd.key.CheckerKt --no-auto-mode --proof-path src/main/key | ||
|
||
checkOverflowCommand=java -Dlogback.configurationFile=./gradle/disablelogging.xml -Dkey.contractOrder="contract-order.txt" -cp "$(KEY_OVERFLOW_JAR):$(CI_TOOL)" de.uka.ilkd.key.CheckerKt -v --no-auto-mode --proof-path src/main/key-overflow | ||
|
||
default: | ||
@echo Available targets: | ||
@sed -n 's/^\([a-zA-Z_-]\+\):.*/ \1/p' Makefile | ||
|
||
proofSettings: | ||
mkdir -p $${HOME}/.key | ||
cp proofIndependentSettings.props $${HOME}/.key | ||
|
||
run: | ||
@echo Consider loading one of the following files: | ||
@find -iname "project*.key" | ||
java -Dkey.contractOrder="contract-order.txt" -jar $(KEY_JAR) | ||
|
||
compile: | ||
find -name "*.java" > sources.txt | ||
javac @sources.txt | ||
|
||
constr-src: | ||
rm -rf src/main/java-constr | ||
cp -r src/main/java src/main/java-constr | ||
sed -i 's/no_state int bucketStart/int bucketStart/' src/main/java-constr/de/wiesler/BucketPointers.java | ||
sed -i 's/no_state int bucketSize/int bucketSize/' src/main/java-constr/de/wiesler/BucketPointers.java | ||
|
||
constr-overflow-src: | ||
rm -rf src/main/java-constr-overflow | ||
cp -r src/main/java src/main/java-constr-overflow | ||
sed -i 's/no_state int bucketStart/int bucketStart/' src/main/java-constr-overflow/de/wiesler/BucketPointers.java | ||
sed -i 's/no_state int bucketSize/int bucketSize/' src/main/java-constr-overflow/de/wiesler/BucketPointers.java | ||
|
||
check: check-methods check-constructors check-overflow-methods check-overflow-constructors | ||
|
||
check-methods: proofSettings | ||
$(checkCommand) --forbid-contracts-file "contracts/ignore.txt" --forbid-contracts-file "contracts/constructors.txt" -s statistics-methods.json src/main/key/project.key | ||
|
||
check-constructors: constr-src | ||
$(checkCommand) --contracts-file contracts/constructors.txt -s statistics-constructors.json src/main/key/project-constr.key | ||
|
||
check-overflow-methods: | ||
$(checkOverflowCommand) --contracts-file "contracts/overflow.txt" --forbid-contracts-file "contracts/constructors.txt" -s statistics-overflow-methods.json src/main/key-overflow/project.key | ||
|
||
check-overflow-constructors: constr-overflow-src | ||
$(checkOverflowCommand) --contracts-file "contracts/constructors.txt" -s statistics-overflow-constructors.json src/main/key-overflow/project-constr.key |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,159 @@ | ||
# Formal Specification and Verification of a Java Implementation of In-Place Super Scalar Sample Sort | ||
# A Formally Verified Efficient Sorting Routine For Java | ||
|
||
This is the verified code and all proof files. | ||
This repostiory contains a sorting routine for Java programs that | ||
combines two important properties that a decent algorithm should have: [2] | ||
1. The implementation is competitively efficient. | ||
2. The implementation is correct in all possible application cases. | ||
|
||
The code in [`src`](src) is based on [this](https://github.com/jwiesler/ips4o) Rust rewrite of the [original paper implementation](https://github.com/ips4o/ips4o). | ||
The first point is shown empirically by benchmarking (see Section 5 of | ||
[2] and the [Sascha Witt's | ||
repository](https://github.com/SaschaWitt/ips4o-java-benchmark)). The | ||
correctness of the implementation has been formally proven using the | ||
[deductive verification engine KeY](https://www.key-project.org) with | ||
which Java programs can be verified against a formal specification | ||
using the [Java Modeling Language | ||
(JML)](https://www.cs.ucf.edu/~leavens/JML/index.shtml). | ||
|
||
The proofs are located in [`proofs`](proofs) and can be loaded using the KeY binaries in [`tools`](tools). | ||
The [`contracts`](contracts) folder contains listing of subsets of all contracts used for filtering. | ||
The proof statistics can be found in [`statistics`](statistics). | ||
You can use the algorithm in your Java programs by declaring a | ||
maven/gradle dependency in your project (s. below). | ||
|
||
## In-Place Super Scalar Sample Sort | ||
|
||
The sorting algorithm [1] implemented in this project is a Java | ||
implementation of in-place super scalar sample sort (ips4o), an award | ||
winning highly efficient sorting routine that was algorithmically | ||
engineered to make use of CPU features like caching, predictive | ||
execution or SIMD. | ||
|
||
The [source code](src/main/java) is based on [this Rust | ||
rewrite](https://github.com/jwiesler/ips4o) of the [original paper | ||
implementation](https://github.com/ips4o/ips4o). | ||
|
||
The source code comprises approximately 900 lines of code. The JML | ||
specification that annotates the Java code (in comments) adds another | ||
2500 lines to the sources. | ||
|
||
## Using ips4o in your project | ||
|
||
You can use the following [maven coordinates](todo) to use `ips4o` in your JVM projects. | ||
|
||
|
||
```groovy | ||
dependencies { | ||
implementation("org.key-project.ips4o:ips4o-verify:1.0") | ||
} | ||
``` | ||
|
||
```xml | ||
<dependency> | ||
<groupId>org.key-project.ips4o</groupId> | ||
<artifactId>ips4o-verify</artifactId> | ||
<version>1.0</version> | ||
</dependency> | ||
``` | ||
|
||
## Verified Properties | ||
|
||
In this case study, the following properties of the Java ips4o implementation | ||
have been specified and successfully verified: | ||
1. **Sorting Property:** The array is sorted after the method invocation. | ||
2. **Permutation Property:** The content of the input array after sorting is a permutation of the initial content. | ||
3. **Exception Safety:** No uncaught exceptions are thrown. | ||
4. **Memory Safety:** The implementation does not modify any previously allocated memory location except the entries of the input array. | ||
5. **Termination:** Every method invocation terminates. | ||
6. **Absence of Overflows:** During the execution of the method, no integer operation will overflow or underflow. | ||
|
||
The top-level specification of the sorting routine reads as follows: | ||
``` | ||
/*@ public normal_behaviour | ||
@ requires values.length <= Buffers.MAX_LEN; | ||
@ | ||
@ ensures \dl_seqPerm(\dl_array2seq(values), \old(\dl_array2seq(values))); | ||
@ ensures Functions.isSortedSlice(values, 0, values.length); | ||
@ | ||
@ assignable values[*]; | ||
@*/ | ||
public static void sort(int[] values) { ... } | ||
``` | ||
|
||
This repository contains the verified code incl. the specification and all proof files. | ||
|
||
## Usage | ||
You can either run the respective KeY binaries in [`tools`](tools) or take some inspiration from the [`justfile`](justfile). | ||
|
||
Make sure to pass `-Dkey.contractOrder="<path to contract-order.txt>"` to java such that the contract order file is loaded. | ||
### Compilation | ||
|
||
In order to compile the sources invoke | ||
``` | ||
./gradlew compileJava | ||
``` | ||
|
||
In order to obtain a jar file with the binary class files of the implementation invoke | ||
``` | ||
./gradlew jar | ||
``` | ||
and find the jar file in `./build/libs/ips4o-verify-1.0.jar`. | ||
|
||
### Verification | ||
|
||
In order to check / redo the proofs, you can load the interactive interface of KeY using | ||
``` | ||
make run | ||
``` | ||
|
||
To check whether all proofs can be replpayed, invoke | ||
``` | ||
make check | ||
``` | ||
This may take some time (possible hours). | ||
|
||
You find the respective KeY binaries in the directory | ||
[`tools`](tools). The [`Makefile`](Makefile) gives you hints on how to | ||
execute the checker. | ||
|
||
The proofs are located in [`proofs`](proofs) and can be loaded using | ||
the KeY binaries in [`tools`](tools). | ||
|
||
The [`contracts`](contracts) folder contains listing of subsets of all | ||
contracts used for filtering. The proof statistics can be found in | ||
[`statistics`](statistics). | ||
|
||
|
||
Make sure to pass `-Dkey.contractOrder="<path to contract-order.txt>"` | ||
to java such that the contract order file is loaded. | ||
|
||
## Caveats | ||
* Overflow proofs and annotations can be found on the branch `overflow`. They have to be loaded using the second KeY binary [`key-2.11.0-o-exe.jar`](tools/key-2.11.0-o-exe.jar). | ||
* To run proofs in [`contracts/constructors.txt`](contracts/constructors.txt) the `no_state` modifier on `BucketPointers::bucketStart` and `BucketPointers::bucketSize` has to be removed. Both methods are only `no_state` when using the final heap which has a soundness problem with constructors. There is currently no nicer way to do this in KeY automatically. | ||
|
||
* The overflow proofs have been conducted after the other proofs. The | ||
annotated sources can be found under | ||
[`src/main/java-overflow`](src/main/java-overflow). In them most | ||
artifacts are assumed without proving them (using the `_free`) since | ||
they have been shown in the original proof obligations. They have | ||
to be loaded using the second KeY binary | ||
[`key-2.11.0-o-exe.jar`](tools/key-2.11.0-o-exe.jar). | ||
|
||
* To run proofs in | ||
[`contracts/constructors.txt`](contracts/constructors.txt) the | ||
`no_state` modifier on `BucketPointers::bucketStart` and | ||
`BucketPointers::bucketSize` has to be removed. Both methods are | ||
only `no_state` when using the final heap which has a soundness | ||
problem with constructors. There is currently no nicer way to do | ||
this in KeY automatically. The Makefile takes care of this | ||
adaptation. | ||
|
||
* The methods `Tree::classify`, `Tree::classify_all` as well as `Tree::build` were left out as future work. | ||
|
||
* To run the code use the `bench` branch which has the proper fallback sorting algorithm not commented out. | ||
|
||
* The sampling function `Functions::select_n` is left empty and should probably be implemented. | ||
|
||
## Publications | ||
|
||
1. Axtmann, M., Ferizovic, D., Sanders, P., Witt, S.: [*Engineering | ||
in-place (shared- memory) sorting | ||
algorithms*](https://dl.acm.org/doi/full/10.1145/3505286). ACM | ||
Transaction on Parallel Computing 9(1), 2:1– 2:62 (2022), see also | ||
[github.com/ips4o](https://github.com/ips4o). Conference version in | ||
ESA 2017 | ||
|
||
2. B. Beckert, P. Sanders, M. Ulbrich, J. Wiesler, and S. Witt: | ||
*Formally Verifying an Efficient Sorter*. arxiv |
Oops, something went wrong.