From 0b3df7f96448df149e61742444967537acc36141 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 15 Jan 2021 12:59:47 -0800 Subject: [PATCH] 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 --- .github/workflows/ci.yml | 73 +++++++++++++++++++++++++++ tests/test_builtin_casters.cpp | 4 +- tests/test_callbacks.cpp | 3 +- tests/test_class.cpp | 2 + tests/test_custom_type_casters.cpp | 13 ++--- tests/test_eigen.cpp | 9 ++-- tests/test_methods_and_attributes.cpp | 20 ++++---- tests/test_numpy_array.cpp | 22 ++++---- 8 files changed, 115 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23dfbb0c9..277103531 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -412,6 +412,7 @@ jobs: - name: Interface test run: cmake3 --build build --target test_cmake_build + # Testing on GCC using the GCC docker images (only recent images supported) gcc: runs-on: ubuntu-latest @@ -464,6 +465,78 @@ jobs: 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 # to get GCC 4.8, which is the manylinux1 compiler). centos: diff --git a/tests/test_builtin_casters.cpp b/tests/test_builtin_casters.cpp index e16c2d62b..79144594c 100644 --- a/tests/test_builtin_casters.cpp +++ b/tests/test_builtin_casters.cpp @@ -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("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 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 m.def("refwrap_builtin", [](std::reference_wrapper p) { return 10 * p.get(); }); diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp index 683dfb3ef..a29a3db7b 100644 --- a/tests/test_callbacks.cpp +++ b/tests/test_callbacks.cpp @@ -119,7 +119,8 @@ TEST_SUBMODULE(callbacks, m) { class AbstractBase { public: - virtual ~AbstractBase() = default; + // [workaround(intel)] = default does not work here + virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default) virtual unsigned int func() = 0; }; m.def("func_accepting_func_accepting_base", [](std::function) { }); diff --git a/tests/test_class.cpp b/tests/test_class.cpp index 523d954c5..43b3ff9d3 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -323,6 +323,8 @@ TEST_SUBMODULE(class_, m) { class PublicistB : public ProtectedB { public: + // [workaround(intel)] = default does not work here + ~PublicistB() override {}; // NOLINT(modernize-use-equals-default) using ProtectedB::foo; }; diff --git a/tests/test_custom_type_casters.cpp b/tests/test_custom_type_casters.cpp index d565add26..3fe910d49 100644 --- a/tests/test_custom_type_casters.cpp +++ b/tests/test_custom_type_casters.cpp @@ -99,19 +99,20 @@ TEST_SUBMODULE(custom_type_casters, m) { } 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_(m, "ArgInspector") .def(py::init<>()) .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_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; }, - 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_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); - m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); - m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); + m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a); + m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert()); + m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a); + m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert()); // test_custom_caster_destruction // Test that `take_ownership` works on types with a custom type caster when given a pointer diff --git a/tests/test_eigen.cpp b/tests/test_eigen.cpp index 2cc2243d6..843254743 100644 --- a/tests/test_eigen.cpp +++ b/tests/test_eigen.cpp @@ -273,6 +273,7 @@ TEST_SUBMODULE(eigen, m) { m.def("cpp_ref_r", [](py::handle m) { return m.cast>()(1, 0); }); m.def("cpp_ref_any", [](py::handle m) { return m.cast>()(1, 0); }); + // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // test_nocopy_wrapper // 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); // Now this alternative that calls the tells pybind to fail rather than copy: m.def("get_elem_nocopy", [](Eigen::Ref m) -> double { return get_elem(m); }, - py::arg().noconvert()); + py::arg{}.noconvert()); // Also test a row-major-only no-copy const ref: m.def("get_elem_rm_nocopy", [](Eigen::Ref> &m) -> long { return m(2, 1); }, - py::arg().noconvert()); + py::arg{}.noconvert()); // test_issue738 // 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 // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. - m.def("iss738_f1", &adjust_matrix &>, py::arg().noconvert()); - m.def("iss738_f2", &adjust_matrix> &>, py::arg().noconvert()); + m.def("iss738_f1", &adjust_matrix &>, py::arg{}.noconvert()); + m.def("iss738_f2", &adjust_matrix> &>, py::arg{}.noconvert()); // test_issue1105 // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp index 6a2cfb6f7..f99909bda 100644 --- a/tests/test_methods_and_attributes.cpp +++ b/tests/test_methods_and_attributes.cpp @@ -322,22 +322,24 @@ TEST_SUBMODULE(methods_and_attributes, m) { 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 py::class_>(m, "NoneTester") .def(py::init<>()); - m.def("no_none1", &none1, 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_none4", &none4, py::arg().none(false)); - m.def("no_none5", &none5, 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_none3", &none3, py::arg{}.none(false)); + m.def("no_none4", &none4, py::arg{}.none(false)); + m.def("no_none5", &none5, py::arg{}.none(false)); 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_none4", &none4, py::arg().none(true)); + m.def("ok_none4", &none4, py::arg{}.none(true)); m.def("ok_none5", &none5); - m.def("no_none_kwarg", &none2, py::arg("a").none(false)); - m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), 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(), "a"_a.none(false)); // test_str_issue // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid diff --git a/tests/test_numpy_array.cpp b/tests/test_numpy_array.cpp index a84de77f8..dca7145f9 100644 --- a/tests/test_numpy_array.cpp +++ b/tests/test_numpy_array.cpp @@ -258,9 +258,11 @@ TEST_SUBMODULE(numpy_array, sm) { sm.def("overloaded2", [](py::array_t>) { return "float complex"; }); sm.def("overloaded2", [](py::array_t) { return "float"; }); + // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. + // Only accept the exact types: - sm.def("overloaded3", [](py::array_t) { return "int"; }, py::arg().noconvert()); - sm.def("overloaded3", [](py::array_t) { return "double"; }, py::arg().noconvert()); + sm.def("overloaded3", [](py::array_t) { return "int"; }, py::arg{}.noconvert()); + sm.def("overloaded3", [](py::array_t) { return "double"; }, py::arg{}.noconvert()); // 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: @@ -284,7 +286,7 @@ TEST_SUBMODULE(numpy_array, sm) { for (py::ssize_t i = 0; i < r.shape(0); i++) for (py::ssize_t j = 0; j < r.shape(1); j++) r(i, j) += v; - }, py::arg().noconvert(), py::arg()); + }, py::arg{}.noconvert(), py::arg()); sm.def("proxy_init3", [](double start) { py::array_t 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 j = 0; j < r.shape(1); j++) r(i, j) += v; - }, py::arg().noconvert(), py::arg()); + }, py::arg{}.noconvert(), py::arg()); sm.def("proxy_init3_dyn", [](double start) { py::array_t a({ 3, 3, 3 }); auto r = a.mutable_unchecked(); @@ -419,20 +421,20 @@ TEST_SUBMODULE(numpy_array, sm) { py::arg("a")); sm.def("accept_double_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); sm.def("accept_double_forcecast_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); sm.def("accept_double_c_style_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); sm.def("accept_double_c_style_forcecast_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); sm.def("accept_double_f_style_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); sm.def("accept_double_f_style_forcecast_noconvert", [](py::array_t) {}, - py::arg("a").noconvert()); + "a"_a.noconvert()); }