ci: Intel icc/icpc via oneAPI (#2573)

* CI: Intel icc/icpc via oneAPI

Add testing for Intel icc/icpc via the oneAPI images.
Intel oneAPI is in a late beta stage, currently shipping
oneAPI beta09 with ICC 20.2.

* CI: Skip Interpreter Tests for Intel

Cannot find how to add this, neiter the package `libc6-dev` nor
`intel-oneapi-mkl-devel` help when installed to solve this:
```
-- Looking for C++ include pthread.h
-- Looking for C++ include pthread.h - not found
CMake Error at /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message):
  Could NOT find Threads (missing: Threads_FOUND)
Call Stack (most recent call first):
  /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE)
  /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindThreads.cmake:234 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
  tests/test_embed/CMakeLists.txt:17 (find_package)
```

* CI: libc6-dev from GCC for ICC

* CI: Run bare metal for oneAPI

* CI: Ubuntu 18.04 for oneAPI

* CI: Intel +Catch -Eigen

* CI: CMake from Apt (ICC tests)

* CI: Replace Intel Py with GCC Py

* CI: Intel w/o GCC's Eigen

* CI: ICC with verbose make

* [Debug] Find core dump

* tests: use arg{} instead of arg() for Intel

* tests: adding a few more missing {}

* fix: sync with @tobiasleibner's branch

* fix: try ubuntu 20-04

* fix: drop exit 1

* style: clang tidy fix

* style: fix missing NOLINT

* ICC: Update Compiler Name

Changed upstream with the last oneAPI release.

* ICC CI: Downgrade pytest

pytest 6 does not capture the `discard_as_unraisable` stderr and
just writes a warning with its content instead.

* Use new test pinning requirements.txt

* tests: add notes about intel, cleanup

Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
This commit is contained in:
Axel Huebl 2021-01-15 12:59:47 -08:00 committed by GitHub
parent 0f8d5f2eb6
commit 0b3df7f964
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 31 deletions

View File

@ -412,6 +412,7 @@ jobs:
- name: Interface test - name: Interface test
run: cmake3 --build build --target test_cmake_build run: cmake3 --build build --target test_cmake_build
# Testing on GCC using the GCC docker images (only recent images supported) # Testing on GCC using the GCC docker images (only recent images supported)
gcc: gcc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -464,6 +465,78 @@ jobs:
run: cmake --build build --target test_cmake_build run: cmake --build build --target test_cmake_build
# Testing on ICC using the oneAPI apt repo
icc:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
name: "🐍 3 • ICC latest • x64"
steps:
- uses: actions/checkout@v1
- name: Add apt repo
run: |
sudo apt-get update
sudo apt-get install -y wget build-essential pkg-config cmake ca-certificates gnupg
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
- name: Add ICC & Python 3
run: sudo apt-get update; sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic cmake python3-dev python3-numpy python3-pytest python3-pip
- name: Update pip
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
python3 -m pip install --upgrade pip
- name: Install dependencies
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
python3 -m pip install -r tests/requirements.txt --prefer-binary
- name: Configure
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
cmake -S . -B build \
-DPYBIND11_WERROR=ON \
-DDOWNLOAD_CATCH=ON \
-DDOWNLOAD_EIGEN=OFF \
-DCMAKE_CXX_STANDARD=11 \
-DCMAKE_CXX_COMPILER=$(which icpc) \
-DCMAKE_VERBOSE_MAKEFILE=ON \
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
- name: Build
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
cmake --build build -j 2
- name: Python tests
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
sudo service apport stop
cmake --build build --target check
- name: C++ tests
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
cmake --build build --target cpptest
- name: Interface test
shell: bash
run: |
set +e; source /opt/intel/oneapi/setvars.sh; set -e
cmake --build build --target test_cmake_build
# Testing on CentOS (manylinux uses a centos base, and this is an easy way # Testing on CentOS (manylinux uses a centos base, and this is an easy way
# to get GCC 4.8, which is the manylinux1 compiler). # to get GCC 4.8, which is the manylinux1 compiler).
centos: centos:

View File

@ -183,9 +183,11 @@ TEST_SUBMODULE(builtin_casters, m) {
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; }); m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// test_bool_caster // test_bool_caster
m.def("bool_passthrough", [](bool arg) { return arg; }); m.def("bool_passthrough", [](bool arg) { return arg; });
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert()); m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
// test_reference_wrapper // test_reference_wrapper
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); }); m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });

View File

@ -119,7 +119,8 @@ TEST_SUBMODULE(callbacks, m) {
class AbstractBase { class AbstractBase {
public: public:
virtual ~AbstractBase() = default; // [workaround(intel)] = default does not work here
virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default)
virtual unsigned int func() = 0; virtual unsigned int func() = 0;
}; };
m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { }); m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });

View File

@ -323,6 +323,8 @@ TEST_SUBMODULE(class_, m) {
class PublicistB : public ProtectedB { class PublicistB : public ProtectedB {
public: public:
// [workaround(intel)] = default does not work here
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
using ProtectedB::foo; using ProtectedB::foo;
}; };

View File

@ -99,19 +99,20 @@ TEST_SUBMODULE(custom_type_casters, m) {
} }
static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
}; };
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
py::class_<ArgInspector>(m, "ArgInspector") py::class_<ArgInspector>(m, "ArgInspector")
.def(py::init<>()) .def(py::init<>())
.def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
.def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts())
.def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts()) .def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts())
; ;
m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; },
py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); py::arg{}.noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts());
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a);
m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
// test_custom_caster_destruction // test_custom_caster_destruction
// Test that `take_ownership` works on types with a custom type caster when given a pointer // Test that `take_ownership` works on types with a custom type caster when given a pointer

View File

@ -273,6 +273,7 @@ TEST_SUBMODULE(eigen, m) {
m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); }); m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
m.def("cpp_ref_any", [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); }); m.def("cpp_ref_any", [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// test_nocopy_wrapper // test_nocopy_wrapper
// Test that we can prevent copying into an argument that would normally copy: First a version // Test that we can prevent copying into an argument that would normally copy: First a version
@ -280,17 +281,17 @@ TEST_SUBMODULE(eigen, m) {
m.def("get_elem", &get_elem); m.def("get_elem", &get_elem);
// Now this alternative that calls the tells pybind to fail rather than copy: // Now this alternative that calls the tells pybind to fail rather than copy:
m.def("get_elem_nocopy", [](Eigen::Ref<const Eigen::MatrixXd> m) -> double { return get_elem(m); }, m.def("get_elem_nocopy", [](Eigen::Ref<const Eigen::MatrixXd> m) -> double { return get_elem(m); },
py::arg().noconvert()); py::arg{}.noconvert());
// Also test a row-major-only no-copy const ref: // Also test a row-major-only no-copy const ref:
m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); }, m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); },
py::arg().noconvert()); py::arg{}.noconvert());
// test_issue738 // test_issue738
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an // Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
// incompatible stride value on the length-1 dimension--but that should be allowed (without // incompatible stride value on the length-1 dimension--but that should be allowed (without
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
m.def("iss738_f1", &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, py::arg().noconvert()); m.def("iss738_f1", &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, py::arg{}.noconvert());
m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg().noconvert()); m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg{}.noconvert());
// test_issue1105 // test_issue1105
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense

View File

@ -322,22 +322,24 @@ TEST_SUBMODULE(methods_and_attributes, m) {
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType()); m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
}); });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// test_accepts_none // test_accepts_none
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester") py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
.def(py::init<>()); .def(py::init<>());
m.def("no_none1", &none1, py::arg().none(false)); m.def("no_none1", &none1, py::arg{}.none(false));
m.def("no_none2", &none2, py::arg().none(false)); m.def("no_none2", &none2, py::arg{}.none(false));
m.def("no_none3", &none3, py::arg().none(false)); m.def("no_none3", &none3, py::arg{}.none(false));
m.def("no_none4", &none4, py::arg().none(false)); m.def("no_none4", &none4, py::arg{}.none(false));
m.def("no_none5", &none5, py::arg().none(false)); m.def("no_none5", &none5, py::arg{}.none(false));
m.def("ok_none1", &none1); m.def("ok_none1", &none1);
m.def("ok_none2", &none2, py::arg().none(true)); m.def("ok_none2", &none2, py::arg{}.none(true));
m.def("ok_none3", &none3); m.def("ok_none3", &none3);
m.def("ok_none4", &none4, py::arg().none(true)); m.def("ok_none4", &none4, py::arg{}.none(true));
m.def("ok_none5", &none5); m.def("ok_none5", &none5);
m.def("no_none_kwarg", &none2, py::arg("a").none(false)); m.def("no_none_kwarg", &none2, "a"_a.none(false));
m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), py::arg("a").none(false)); m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), "a"_a.none(false));
// test_str_issue // test_str_issue
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid

View File

@ -258,9 +258,11 @@ TEST_SUBMODULE(numpy_array, sm) {
sm.def("overloaded2", [](py::array_t<std::complex<float>>) { return "float complex"; }); sm.def("overloaded2", [](py::array_t<std::complex<float>>) { return "float complex"; });
sm.def("overloaded2", [](py::array_t<float>) { return "float"; }); sm.def("overloaded2", [](py::array_t<float>) { return "float"; });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// Only accept the exact types: // Only accept the exact types:
sm.def("overloaded3", [](py::array_t<int>) { return "int"; }, py::arg().noconvert()); sm.def("overloaded3", [](py::array_t<int>) { return "int"; }, py::arg{}.noconvert());
sm.def("overloaded3", [](py::array_t<double>) { return "double"; }, py::arg().noconvert()); sm.def("overloaded3", [](py::array_t<double>) { return "double"; }, py::arg{}.noconvert());
// Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but
// rather that float gets converted via the safe (conversion to double) overload: // rather that float gets converted via the safe (conversion to double) overload:
@ -284,7 +286,7 @@ TEST_SUBMODULE(numpy_array, sm) {
for (py::ssize_t i = 0; i < r.shape(0); i++) for (py::ssize_t i = 0; i < r.shape(0); i++)
for (py::ssize_t j = 0; j < r.shape(1); j++) for (py::ssize_t j = 0; j < r.shape(1); j++)
r(i, j) += v; r(i, j) += v;
}, py::arg().noconvert(), py::arg()); }, py::arg{}.noconvert(), py::arg());
sm.def("proxy_init3", [](double start) { sm.def("proxy_init3", [](double start) {
py::array_t<double, py::array::c_style> a({ 3, 3, 3 }); py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
@ -338,7 +340,7 @@ TEST_SUBMODULE(numpy_array, sm) {
for (py::ssize_t i = 0; i < r.shape(0); i++) for (py::ssize_t i = 0; i < r.shape(0); i++)
for (py::ssize_t j = 0; j < r.shape(1); j++) for (py::ssize_t j = 0; j < r.shape(1); j++)
r(i, j) += v; r(i, j) += v;
}, py::arg().noconvert(), py::arg()); }, py::arg{}.noconvert(), py::arg());
sm.def("proxy_init3_dyn", [](double start) { sm.def("proxy_init3_dyn", [](double start) {
py::array_t<double, py::array::c_style> a({ 3, 3, 3 }); py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
auto r = a.mutable_unchecked(); auto r = a.mutable_unchecked();
@ -419,20 +421,20 @@ TEST_SUBMODULE(numpy_array, sm) {
py::arg("a")); py::arg("a"));
sm.def("accept_double_noconvert", sm.def("accept_double_noconvert",
[](py::array_t<double, 0>) {}, [](py::array_t<double, 0>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
sm.def("accept_double_forcecast_noconvert", sm.def("accept_double_forcecast_noconvert",
[](py::array_t<double, py::array::forcecast>) {}, [](py::array_t<double, py::array::forcecast>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
sm.def("accept_double_c_style_noconvert", sm.def("accept_double_c_style_noconvert",
[](py::array_t<double, py::array::c_style>) {}, [](py::array_t<double, py::array::c_style>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
sm.def("accept_double_c_style_forcecast_noconvert", sm.def("accept_double_c_style_forcecast_noconvert",
[](py::array_t<double, py::array::forcecast | py::array::c_style>) {}, [](py::array_t<double, py::array::forcecast | py::array::c_style>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
sm.def("accept_double_f_style_noconvert", sm.def("accept_double_f_style_noconvert",
[](py::array_t<double, py::array::f_style>) {}, [](py::array_t<double, py::array::f_style>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
sm.def("accept_double_f_style_forcecast_noconvert", sm.def("accept_double_f_style_forcecast_noconvert",
[](py::array_t<double, py::array::forcecast | py::array::f_style>) {}, [](py::array_t<double, py::array::forcecast | py::array::f_style>) {},
py::arg("a").noconvert()); "a"_a.noconvert());
} }