From 9d7616317e981b808a5ddbb08031da4b94d3093c Mon Sep 17 00:00:00 2001 From: Viktor Lofgren Date: Thu, 16 May 2024 14:47:10 +0200 Subject: [PATCH] (array) Clean up native code a bit --- code/libraries/array/cpp/build.gradle | 2 +- code/libraries/array/cpp/compile.sh | 6 +- .../cpp/java/nu/marginalia/NativeAlgos.java | 2 + .../array/cpp/src/main/cpp/cpphelpers.cpp | 56 ++++++------------- .../array/algo/LongArraySortTest.java | 2 +- 5 files changed, 25 insertions(+), 43 deletions(-) diff --git a/code/libraries/array/cpp/build.gradle b/code/libraries/array/cpp/build.gradle index 8d4311b2..20ce4207 100644 --- a/code/libraries/array/cpp/build.gradle +++ b/code/libraries/array/cpp/build.gradle @@ -18,7 +18,7 @@ apply from: "$rootProject.projectDir/srcsets.gradle" // with a shellscript as gradle's c++ tasks are kind of insufferable tasks.register('compileCpp', Exec) { - inputs.files('src/main/cpp/cpphelpers.cpp', 'src/main/public/cpphelpers.h') + inputs.files('compile.sh', 'src/main/cpp/cpphelpers.cpp', 'src/main/public/cpphelpers.h') outputs.file 'resources/libcpp.so' commandLine 'sh', 'compile.sh' } diff --git a/code/libraries/array/cpp/compile.sh b/code/libraries/array/cpp/compile.sh index 0e022970..89c6d1d6 100644 --- a/code/libraries/array/cpp/compile.sh +++ b/code/libraries/array/cpp/compile.sh @@ -1,8 +1,10 @@ #!/usr/bin/env sh -if ! which g++ > /dev/null; then +CXX=${CXX:-g++} + +if ! which ${CXX} > /dev/null; then echo "g++ not found, skipping compilation" exit 0 fi -c++ -c -O3 -march=native -shared -fPIC -Isrc/main/public src/main/cpp/*.cpp -o resources/libcpp.so \ No newline at end of file +${CXX} -O3 -march=native -shared -Isrc/main/public src/main/cpp/*.cpp -o resources/libcpp.so \ No newline at end of file diff --git a/code/libraries/array/cpp/java/nu/marginalia/NativeAlgos.java b/code/libraries/array/cpp/java/nu/marginalia/NativeAlgos.java index cd8bc818..ce203101 100644 --- a/code/libraries/array/cpp/java/nu/marginalia/NativeAlgos.java +++ b/code/libraries/array/cpp/java/nu/marginalia/NativeAlgos.java @@ -80,12 +80,14 @@ public class NativeAlgos { try (var os = new FileOutputStream(tempFile)) { is.transferTo(os); + os.flush(); } libFile = tempFile.toPath(); nativeAlgosI = new NativeAlgos(libFile); } catch (Exception e) { + e.printStackTrace(); logger.info("Failed to load native library, likely not built"); } diff --git a/code/libraries/array/cpp/src/main/cpp/cpphelpers.cpp b/code/libraries/array/cpp/src/main/cpp/cpphelpers.cpp index f359b512..f49f7d7b 100644 --- a/code/libraries/array/cpp/src/main/cpp/cpphelpers.cpp +++ b/code/libraries/array/cpp/src/main/cpp/cpphelpers.cpp @@ -2,7 +2,17 @@ #include #include -struct p2 { +/* Pair of 64-bit integers. */ +/* The struct is packed to ensure that the struct is exactly 16 bytes in size, as we need to pointer + alias on an array of 8 byte longs. Since structs guarantee that the first element is at offset 0, + and __attribute__((packed)) guarantees that the struct is exactly 16 bytes in size, the only reasonable + implementation is that the struct is laid out as 2 64-bit integers. This assumption works only as + long as there are at most 2 fields. + + This is a non-portable low level hack, but all this code strongly assumes a x86-64 Linux environment. + For other environments (e.g. outside of prod), the Java implementation code will have to do. +*/ +struct __attribute__((packed)) p64x2 { int64_t a; int64_t b; }; @@ -12,29 +22,21 @@ void ms_sort_64(int64_t* area, uint64_t start, uint64_t end) { } void ms_sort_128(int64_t* area, uint64_t start, uint64_t end) { - struct p2 *startp = (struct p2 *) &area[start]; - struct p2 *endp = (struct p2 *) &area[end]; - - // sort based on the first element of the pair - std::sort(startp, endp, [](struct p2& fst, struct p2& snd) { + std::sort( + reinterpret_cast(&area[start]), + reinterpret_cast(&area[end]), + [](const p64x2& fst, const p64x2& snd) { return fst.a < snd.a; }); } -int64_t encodeSearchMiss64(int64_t value) { +inline int64_t encodeSearchMiss64(int64_t value) { return -1 - std::max(int64_t(0), value); } -int64_t encodeSearchMiss128(int64_t value) { +inline int64_t encodeSearchMiss128(int64_t value) { return -2 - std::max(int64_t(0), value); } -int64_t decodeSearchMiss64(long value) { - return -value - 1; -} -int64_t decodeSearchMiss128(long value) { - return -value - 2; -} - int64_t ms_linear_search_64(int64_t key, int64_t* area, uint64_t fromIndex, uint64_t toIndex) { uint64_t pos = fromIndex; for (; pos < toIndex; pos++) { @@ -60,30 +62,6 @@ int64_t ms_linear_search_128(int64_t key, int64_t* area, uint64_t fromIndex, uin return encodeSearchMiss128(pos - 2); } -/** long low = 0; - long high = (toIndex - fromIndex)/sz - 1; - - while (high - low >= LINEAR_SEARCH_CUTOFF) { - long mid = (low + high) >>> 1; - long midVal = get(fromIndex + sz*mid); - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return fromIndex + sz*mid; - } - - for (fromIndex += low*sz; fromIndex < toIndex; fromIndex+=sz) { - long val = get(fromIndex); - - if (val == key) return fromIndex; - if (val > key) return encodeSearchMiss(sz, fromIndex); - } - - return encodeSearchMiss(sz, toIndex - sz); */ - int64_t ms_binary_search_128(int64_t key, int64_t* area, uint64_t fromIndex, uint64_t toIndex) { int64_t low = 0; int64_t high = (toIndex - fromIndex) / 2 - 1; diff --git a/code/libraries/array/test/nu/marginalia/array/algo/LongArraySortTest.java b/code/libraries/array/test/nu/marginalia/array/algo/LongArraySortTest.java index 2024e105..5c5530b0 100644 --- a/code/libraries/array/test/nu/marginalia/array/algo/LongArraySortTest.java +++ b/code/libraries/array/test/nu/marginalia/array/algo/LongArraySortTest.java @@ -86,7 +86,7 @@ class LongArraySortTest { @Test public void quickSortStressTest() throws IOException { LongArray array = LongArray.allocate(65536); - sortAlgorithmTester(array, LongArraySort::quickSort); + sortAlgorithmTester(array, LongArraySort::quickSortJava); } @Test