diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java new file mode 100644 index 0000000..c114f4b --- /dev/null +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java @@ -0,0 +1,47 @@ +package de.uni_marburg.powersort.benchmark; + +import de.uni_marburg.powersort.TimSort; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +// TODO: The parameters are way too low. Use for debugging only! +@Fork(0) +@Warmup(iterations = 0) +@Measurement(iterations = 3) +public class BenchmarkJmh { + @State(Scope.Benchmark) + public static class State1 { + Integer[] readOnly = IntegerArray.random(500_000);; + Integer[] a; + + @Setup(Level.Invocation) + public void setup() { + a = Arrays.copyOf(readOnly, readOnly.length); + } + } + + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @Benchmark + public void rand1DummySort(State1 s, Blackhole bh) { + DummySort.sort(s.a, 0, s.a.length, NaturalOrder.INSTANCE, null, 0, 0); + } + + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @Benchmark + public void rand1TimSort(State1 s, Blackhole bh) { + TimSort.sort(s.a, 0, s.a.length, NaturalOrder.INSTANCE, null, 0, 0); + bh.consume(s); + } + + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @Benchmark + public void rand1MergeSort(State1 s) { + MergeSort.legacyMergeSort(s.a, NaturalOrder.INSTANCE); + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java new file mode 100644 index 0000000..dcc9069 --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java @@ -0,0 +1,18 @@ +package de.uni_marburg.powersort.benchmark; + +public class IntegerArray { + private IntegerArray() { + } + + public static Integer[] random(final int length) { + return random(length, Integer.MIN_VALUE, Integer.MAX_VALUE); + } + + public static Integer[] random(final int length, final int minInt, final int maxInt) { + final Integer[] list = new Integer[length]; + for (int i = 0; i < length; i++) { + list[i] = RandomInt.integer(minInt, maxInt); + } + return list; + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index fe0e492..adadf7c 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -6,6 +6,9 @@ import java.util.Arrays; import java.util.List; import java.util.function.Supplier; +/** + * Custom benchmark. + */ public class Main { public static void main(final String[] args) { final SortImpl[] sortImplementations = getSortImplementations(); diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/MergeSort.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/MergeSort.java new file mode 100644 index 0000000..8fe72fe --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/MergeSort.java @@ -0,0 +1,78 @@ +package de.uni_marburg.powersort.benchmark; + +import java.util.Comparator; + +/** + * Copied from JDK23 Arrays.java + */ +public class MergeSort { + /** + * Tuning parameter: list size at or below which insertion sort will be + * used in preference to mergesort. + * To be removed in a future release. + */ + private static final int INSERTIONSORT_THRESHOLD = 7; + + /** To be removed in a future release. */ + public static void legacyMergeSort(T[] a, Comparator c) { + T[] aux = a.clone(); + mergeSort(aux, a, 0, a.length, 0, c); + } + + /** + * Src is the source array that starts at index 0 + * Dest is the (possibly larger) array destination with a possible offset + * low is the index in dest to start sorting + * high is the end index in dest to end sorting + * off is the offset into src corresponding to low in dest + * To be removed in a future release. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static void mergeSort(Object[] src, + Object[] dest, + int low, int high, int off, + Comparator c) { + int length = high - low; + + // Insertion sort on smallest arrays + if (length < INSERTIONSORT_THRESHOLD) { + for (int i=low; ilow && c.compare(dest[j-1], dest[j])>0; j--) + swap(dest, j, j-1); + return; + } + + // Recursively sort halves of dest into src + int destLow = low; + int destHigh = high; + low += off; + high += off; + int mid = (low + high) >>> 1; + mergeSort(dest, src, low, mid, -off, c); + mergeSort(dest, src, mid, high, -off, c); + + // If list is already sorted, just copy from src to dest. This is an + // optimization that results in faster sorts for nearly ordered lists. + if (c.compare(src[mid-1], src[mid]) <= 0) { + System.arraycopy(src, low, dest, destLow, length); + return; + } + + // Merge sorted halves (now in src) into dest + for(int i = destLow, p = low, q = mid; i < destHigh; i++) { + if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) + dest[i] = src[p++]; + else + dest[i] = src[q++]; + } + } + + /** + * Swaps x[a] with x[b]. + */ + private static void swap(Object[] x, int a, int b) { + Object t = x[a]; + x[a] = x[b]; + x[b] = t; + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java new file mode 100644 index 0000000..3575cdc --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java @@ -0,0 +1,22 @@ +package de.uni_marburg.powersort.benchmark; + +/** + * Provides utility methods related to random integers. + */ +public final class RandomInt { + private RandomInt() { + } + + /** + * Returns a random integer. + * + * @return A random integer. + */ + public static int integer() { + return integer(Integer.MIN_VALUE, Integer.MAX_VALUE); + } + public static int integer(final int minInt, final int maxInt) { + final double random = Math.random() * (maxInt - minInt) - minInt; + return (int) Math.round(random); + } +} diff --git a/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java b/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java new file mode 100644 index 0000000..733b44d --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java @@ -0,0 +1,36 @@ +package de.uni_marburg.powersort.benchmark; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class RandomIntTest { + protected RandomIntTest(){ + // This constructor is intentionally empty. Nothing special is needed here. + } + + @Test + void testRandomInt() { + final double accuracy = 0.99; + final int min = (int) Math.round(Integer.MIN_VALUE * accuracy); + final int max = (int) Math.round(Integer.MAX_VALUE * accuracy); + + boolean minPassed = false; + boolean maxPassed = false; + for (int i = 0; i < 1000; i++) { + final int random = RandomInt.integer(); + System.out.println(random); //NOPMD - suppressed SystemPrintln - Testing + + if (random <= min) { + minPassed = true; + } + if (random >= max) { + maxPassed = true; + } + if (minPassed && maxPassed) { + return; + } + } + + Assertions.fail("min or max not reached - not a random int generator"); + } +}