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

Fixes some tests/bugs, and adds a build with sanitizers, add ASAN CI run #182

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,80 @@ jobs:
- name: Run test suite on SPR
run: sde -spr -- ./builddir/testexe

ADL-ASAN-clang18:

runs-on: intel-ubuntu-24.04

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Install dependencies
run: |
sudo apt update
sudo apt -y install clang-18 libomp-18-dev libgtest-dev meson curl git

- name: Install Intel SDE
run: |
curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/784319/sde-external-9.24.0-2023-07-13-lin.tar.xz
mkdir /tmp/sde && tar -xvf /tmp/sde.tar.xz -C /tmp/sde/
sudo mv /tmp/sde/* /opt/sde && sudo ln -s /opt/sde/sde64 /usr/bin/sde

- name: Build examples
env:
CXX: clang++-18
run: |
cd examples
make all

- name: Build
env:
CXX: clang++-18
run: |
make clean
meson setup -Dbuild_tests=true -Duse_openmp=true -Db_sanitize=address,undefined -Dfatal_sanitizers=true -Dasan_ci_dont_validate=true -Db_lundef=false --warnlevel 0 --buildtype release builddir
cd builddir
ninja

- name: Run test suite on SPR
run: sde -adl -- ./builddir/testexe

SPR-ASAN-clang18:

runs-on: intel-ubuntu-24.04

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Install dependencies
run: |
sudo apt update
sudo apt -y install clang-18 libomp-18-dev libgtest-dev meson curl git

- name: Install Intel SDE
run: |
curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/784319/sde-external-9.24.0-2023-07-13-lin.tar.xz
mkdir /tmp/sde && tar -xvf /tmp/sde.tar.xz -C /tmp/sde/
sudo mv /tmp/sde/* /opt/sde && sudo ln -s /opt/sde/sde64 /usr/bin/sde

- name: Build examples
env:
CXX: clang++-18
run: |
cd examples
make all

- name: Build
env:
CXX: clang++-18
run: |
make clean
meson setup -Dbuild_tests=true -Duse_openmp=true -Db_sanitize=address,undefined -Dfatal_sanitizers=true -Dasan_ci_dont_validate=true -Db_lundef=false --warnlevel 0 --buildtype release builddir
cd builddir
ninja

- name: Run test suite on SPR
run: sde -spr -- ./builddir/testexe

SKX-SKL-openmp:

runs-on: intel-ubuntu-24.04
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ test_openmp:
meson setup -Dbuild_tests=true -Duse_openmp=true --warnlevel 2 --werror --buildtype release builddir
cd builddir && ninja

test_asan:
meson setup -Dbuild_tests=true -Duse_openmp=true -Db_sanitize=address,undefined -Dfatal_sanitizers=true -Db_lundef=false -Dasan_ci_dont_validate=true --warnlevel 0 --buildtype debugoptimized builddir
cd builddir && ninja

bench:
meson setup -Dbuild_benchmarks=true --warnlevel 2 --werror --buildtype release builddir
cd builddir && ninja
Expand Down
5 changes: 5 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ if get_option('build_ippbench')
ipplink = ['-lipps', '-lippcore']
endif

# Essentially '-Werror' for the sanitizers; all problems become fatal with this set
if get_option('fatal_sanitizers')
add_project_arguments([ '-fno-sanitize-recover=all' ], language: 'cpp')
endif

# Add google vqsort to benchmarks:
benchvq = false
if get_option('build_vqsortbench')
Expand Down
5 changes: 4 additions & 1 deletion meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ option('use_openmp', type : 'boolean', value : false,
description : 'Use OpenMP to accelerate key-value sort (default: "false").')
option('lib_type', type : 'string', value : 'shared',
description : 'Library type: shared or static (default: "shared").')

option('fatal_sanitizers', type : 'boolean', value : 'false',
description : 'If sanitizers are enabled, should all issues be considered fatal? (default: "false").')
option('asan_ci_dont_validate', type : 'boolean', value : 'false',
description : 'Only for speeding up ASAN CI, do not turn on otherwise')
3 changes: 3 additions & 0 deletions src/xss-common-qsort.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,9 @@ xss_qselect(T *arr, arrsize_t k, arrsize_t arrsize, bool hasnan)
Comparator<vtype, true>,
Comparator<vtype, false>>::type;

// Exit early if no work would be done
if (arrsize <= 1) return;

arrsize_t index_first_elem = 0;
arrsize_t index_last_elem = arrsize - 1;

Expand Down
14 changes: 14 additions & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
libtests = []

# Add compile flags when needed for the ASAN CI run
testargs = []
if get_option('asan_ci_dont_validate')
if get_option('fatal_sanitizers')
testargs = ['-DXSS_ASAN_CI_NOCHECK=true']
else
error('asan_ci_dont_validate is only for the ASAN CI, should be false otherwise!')
endif
endif


libtests += static_library('tests_qsort',
files('test-qsort.cpp', ),
dependencies: gtest_dep,
include_directories : [src, lib, utils],
cpp_args : [testargs],
)

libtests += static_library('tests_kvsort',
files('test-keyvalue.cpp', ),
dependencies: gtest_dep,
include_directories : [src, lib, utils],
cpp_args : [testargs],
)

libtests += static_library('tests_objsort',
files('test-objqsort.cpp', ),
dependencies: gtest_dep,
include_directories : [src, lib, utils],
cpp_args : [testargs],
)
47 changes: 32 additions & 15 deletions tests/test-keyvalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class simdkvsort : public ::testing::Test {
public:
simdkvsort()
{
std::iota(arrsize.begin(), arrsize.end(), 1);
std::iota(arrsize.begin(), arrsize.end(), 0);
arrsize.push_back(10'000);
arrsize.push_back(100'000);
arrsize.push_back(1'000'000);
Expand Down Expand Up @@ -58,6 +58,9 @@ bool is_kv_sorted(
{
auto cmp_eq = compare<T1, std::equal_to<T1>>();

// Always true for arrays of zero length
if (size == 0) return true;

// First check keys are exactly identical
for (size_t i = 0; i < size; i++) {
if (!cmp_eq(keys_comp[i], keys_ref[i])) { return false; }
Expand Down Expand Up @@ -173,8 +176,10 @@ TYPED_TEST_P(simdkvsort, test_kvsort_ascending)
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_qsort(
key.data(), val.data(), size, hasnan, false);
#ifndef XSS_ASAN_CI_NOCHECK
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, false);

Expand All @@ -184,7 +189,7 @@ TYPED_TEST_P(simdkvsort, test_kvsort_ascending)
val_bckp.data(),
size);
ASSERT_EQ(is_kv_sorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand All @@ -204,8 +209,10 @@ TYPED_TEST_P(simdkvsort, test_kvsort_descending)
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_qsort(
key.data(), val.data(), size, hasnan, true);
#ifndef XSS_ASAN_CI_NOCHECK
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, true);

Expand All @@ -215,7 +222,7 @@ TYPED_TEST_P(simdkvsort, test_kvsort_descending)
val_bckp.data(),
size);
ASSERT_EQ(is_kv_sorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand All @@ -232,19 +239,21 @@ TYPED_TEST_P(simdkvsort, test_kvselect_ascending)
for (auto type : this->arrtype) {
bool hasnan = is_nan_test(type);
for (auto size : this->arrsize) {
size_t k = rand() % size;
size_t k = size != 0 ? rand() % size : 0;

std::vector<T1> key = get_array<T1>(type, size);
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_select(
key.data(), val.data(), k, size, hasnan, false);
#ifndef XSS_ASAN_CI_NOCHECK
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, false);

// Test select by using it as part of partial_sort
x86simdsort::keyvalue_select(
key.data(), val.data(), k, size, hasnan, false);
if (size == 0) continue;
IS_ARR_PARTITIONED<T1>(key, k, key_bckp[k], type);
xss::scalar::keyvalue_qsort(
key.data(), val.data(), k, hasnan, false);
Expand All @@ -259,7 +268,7 @@ TYPED_TEST_P(simdkvsort, test_kvselect_ascending)
size,
k);
ASSERT_EQ(is_kv_partialsorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand All @@ -276,19 +285,21 @@ TYPED_TEST_P(simdkvsort, test_kvselect_descending)
for (auto type : this->arrtype) {
bool hasnan = is_nan_test(type);
for (auto size : this->arrsize) {
size_t k = rand() % size;
size_t k = size != 0 ? rand() % size : 0;

std::vector<T1> key = get_array<T1>(type, size);
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_select(
key.data(), val.data(), k, size, hasnan, true);
#ifndef XSS_ASAN_CI_NOCHECK
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, true);

// Test select by using it as part of partial_sort
x86simdsort::keyvalue_select(
key.data(), val.data(), k, size, hasnan, true);
if (size == 0) continue;
IS_ARR_PARTITIONED<T1>(key, k, key_bckp[k], type, true);
xss::scalar::keyvalue_qsort(
key.data(), val.data(), k, hasnan, true);
Expand All @@ -303,7 +314,7 @@ TYPED_TEST_P(simdkvsort, test_kvselect_descending)
size,
k);
ASSERT_EQ(is_kv_partialsorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand All @@ -319,14 +330,17 @@ TYPED_TEST_P(simdkvsort, test_kvpartial_sort_ascending)
for (auto type : this->arrtype) {
bool hasnan = is_nan_test(type);
for (auto size : this->arrsize) {
size_t k = rand() % size;
size_t k = size != 0 ? rand() % size : 0;

std::vector<T1> key = get_array<T1>(type, size);
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_partial_sort(
key.data(), val.data(), k, size, hasnan, false);
#ifndef XSS_ASAN_CI_NOCHECK
if (size == 0) continue;
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, false);

Expand All @@ -340,7 +354,7 @@ TYPED_TEST_P(simdkvsort, test_kvpartial_sort_ascending)
size,
k);
ASSERT_EQ(is_kv_partialsorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand All @@ -356,14 +370,17 @@ TYPED_TEST_P(simdkvsort, test_kvpartial_sort_descending)
for (auto type : this->arrtype) {
bool hasnan = is_nan_test(type);
for (auto size : this->arrsize) {
size_t k = rand() % size;
size_t k = size != 0 ? rand() % size : 0;

std::vector<T1> key = get_array<T1>(type, size);
std::vector<T2> val = get_array<T2>(type, size);
std::vector<T1> key_bckp = key;
std::vector<T2> val_bckp = val;

x86simdsort::keyvalue_partial_sort(
key.data(), val.data(), k, size, hasnan, true);
#ifndef XSS_ASAN_CI_NOCHECK
if (size == 0) continue;
xss::scalar::keyvalue_qsort(
key_bckp.data(), val_bckp.data(), size, hasnan, true);

Expand All @@ -377,7 +394,7 @@ TYPED_TEST_P(simdkvsort, test_kvpartial_sort_descending)
size,
k);
ASSERT_EQ(is_kv_partialsorted_, true);

#endif
key.clear();
val.clear();
key_bckp.clear();
Expand Down
2 changes: 1 addition & 1 deletion tests/test-objqsort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class simdobjsort : public ::testing::Test {
public:
simdobjsort()
{
std::iota(arrsize.begin(), arrsize.end(), 1);
std::iota(arrsize.begin(), arrsize.end(), 0);
arrtype = {"random",
"constant",
"sorted",
Expand Down
1 change: 1 addition & 0 deletions tests/test-qsort-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ inline bool is_nan_test(std::string type)
template <typename T>
void IS_SORTED(std::vector<T> sorted, std::vector<T> arr, std::string type)
{
if (arr.size() == 0) return;
if (memcmp(arr.data(), sorted.data(), arr.size() * sizeof(T)) != 0) {
REPORT_FAIL("Array not sorted", arr.size(), type, -1);
}
Expand Down
Loading