You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by zh...@apache.org on 2021/05/21 18:19:12 UTC

[incubator-mxnet] branch v1.x updated: [v1.x] [CD] Add Aarch64 to cd (#20288)

This is an automated email from the ASF dual-hosted git repository.

zhasheng pushed a commit to branch v1.x
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git


The following commit(s) were added to refs/heads/v1.x by this push:
     new 7530e0e  [v1.x] [CD] Add Aarch64 to cd (#20288)
7530e0e is described below

commit 7530e0e1d6bcdf8385586ef0236a2b2d4dc7c9e3
Author: Manu Seth <22...@users.noreply.github.com>
AuthorDate: Fri May 21 11:17:08 2021 -0700

    [v1.x] [CD] Add Aarch64 to cd (#20288)
    
    * add initial cd changes for aarch64
    
    * skip failing aarch64 tests
    
    * skip failing aarch64 tests
    
    * add cd wheel support
    
    * add aarch64 node to cd pypi
    
    * fix dockerfile for aarch64
    
    * fix dockerfile for aarch64
    
    * refer github issue for failing tests
    
    * update pypi package name
    
    * add requirements file for aarch64 for cd docker
---
 cd/Jenkinsfile_cd_pipeline                         |  2 +-
 cd/Jenkinsfile_release_job                         |  5 ++-
 cd/mxnet_lib/Jenkins_pipeline.groovy               | 24 ++++++++----
 cd/mxnet_lib/mxnet_lib_pipeline.groovy             | 11 ++++--
 cd/python/docker/Dockerfile                        |  5 ++-
 cd/python/docker/Dockerfile.test                   |  8 ++--
 cd/python/docker/Jenkins_pipeline.groovy           | 20 ++++++++--
 cd/python/docker/python_images.sh                  |  9 ++++-
 cd/python/pypi/Jenkins_pipeline.groovy             | 22 +++++++++--
 cd/utils/docker_tag.sh                             |  2 +
 cd/utils/mxnet_base_image.sh                       |  3 ++
 ci/Jenkinsfile_utils.groovy                        |  2 +-
 .../docker/install/requirements_aarch64            | 34 ++++++++--------
 python/mxnet/test_utils.py                         |  5 +++
 tests/python/unittest/test_contrib_operator.py     |  1 +
 tests/python/unittest/test_ndarray.py              |  3 ++
 .../python/unittest/test_numpy_interoperability.py |  2 +
 tests/python/unittest/test_numpy_op.py             |  2 +
 tools/pip/doc/AARCH64_CPU_ADDITIONAL.md            | 45 ++++++++++++++++++++++
 tools/pip/setup.py                                 |  4 +-
 tools/staticbuild/build_lib_cmake.sh               |  6 +--
 21 files changed, 162 insertions(+), 53 deletions(-)

diff --git a/cd/Jenkinsfile_cd_pipeline b/cd/Jenkinsfile_cd_pipeline
index 03f2fb1..c3f33a7 100644
--- a/cd/Jenkinsfile_cd_pipeline
+++ b/cd/Jenkinsfile_cd_pipeline
@@ -36,7 +36,7 @@ pipeline {
 
   parameters {
     // Release parameters
-    string(defaultValue: "cpu,native,cu100,cu101,cu102,cu110,cu112", description: "Comma separated list of variants", name: "MXNET_VARIANTS")
+    string(defaultValue: "cpu,native,cu100,cu101,cu102,cu110,cu112,aarch64_cpu", description: "Comma separated list of variants", name: "MXNET_VARIANTS")
     booleanParam(defaultValue: false, description: 'Whether this is a release build or not', name: "RELEASE_BUILD")
   }
 
diff --git a/cd/Jenkinsfile_release_job b/cd/Jenkinsfile_release_job
index 21af1d5..309e66b 100644
--- a/cd/Jenkinsfile_release_job
+++ b/cd/Jenkinsfile_release_job
@@ -43,7 +43,7 @@ pipeline {
     // any disruption caused by different COMMIT_ID values chaning the job parameter configuration on
     // Jenkins.
     string(defaultValue: "mxnet_lib", description: "Pipeline to build", name: "RELEASE_JOB_TYPE")
-    string(defaultValue: "cpu,native,cu100,cu101,cu102,cu110,cu112", description: "Comma separated list of variants", name: "MXNET_VARIANTS")
+    string(defaultValue: "cpu,native,cu100,cu101,cu102,cu110,cu112,aarch64_cpu", description: "Comma separated list of variants", name: "MXNET_VARIANTS")
     booleanParam(defaultValue: false, description: 'Whether this is a release build or not', name: "RELEASE_BUILD")
     string(defaultValue: "nightly_v1.x", description: "String used for naming docker images", name: "VERSION")
   }
@@ -56,9 +56,10 @@ pipeline {
           ci_utils = load('ci/Jenkinsfile_utils.groovy')
           ci_utils.assign_node_labels(
             utility: 'restricted-utility',
+            linux_aarch64_cpu: 'restricted-ub18-c6g',
             linux_cpu: 'restricted-mxnetlinux-cpu',
             linux_gpu: 'restricted-mxnetlinux-gpu',
-            linux_gpu_p3: 'restricted-mxnetlinux-gpu-p3',
+            linux_gpu_g4: 'restricted-mxnetlinux-gpu-g4',
             windows_cpu: 'restricted-mxnetwindows-cpu',
             windows_gpu: 'restricted-mxnetwindows-gpu'
           )
diff --git a/cd/mxnet_lib/Jenkins_pipeline.groovy b/cd/mxnet_lib/Jenkins_pipeline.groovy
index 557a25b..f34988d 100644
--- a/cd/mxnet_lib/Jenkins_pipeline.groovy
+++ b/cd/mxnet_lib/Jenkins_pipeline.groovy
@@ -43,13 +43,23 @@ libmxnet_pipeline = load('cd/mxnet_lib/mxnet_lib_pipeline.groovy')
 
 // Builds the static binary for the specified mxnet variant
 def build(mxnet_variant) {
-  node(NODE_LINUX_CPU) {
-    ws("workspace/mxnet_${libtype}/${mxnet_variant}/${env.BUILD_NUMBER}") {
-      ci_utils.init_git()
-      // Compiling in Ubuntu14.04 due to glibc issues. 
-      // This should be updates once we have clarity on this issue.
-      ci_utils.docker_run('publish.ubuntu1404_cpu', "build_static_libmxnet ${mxnet_variant}", false)
-      ci_utils.pack_lib("mxnet_${mxnet_variant}", libmxnet_pipeline.get_stash(mxnet_variant))
+  if (mxnet_variant.startsWith("aarch64")) {
+    node(NODE_LINUX_AARCH64_CPU) {
+      ws("workspace/mxnet_${libtype}/${mxnet_variant}/${env.BUILD_NUMBER}") {
+        ci_utils.init_git()
+        ci_utils.docker_run('publish.ubuntu1804_aarch64_cpu', "build_static_libmxnet ${mxnet_variant}", false)
+        ci_utils.pack_lib("mxnet_${mxnet_variant}", libmxnet_pipeline.get_stash(mxnet_variant))
+      }
+    }
+  } else {
+    node(NODE_LINUX_CPU) {
+      ws("workspace/mxnet_${libtype}/${mxnet_variant}/${env.BUILD_NUMBER}") {
+        ci_utils.init_git()
+        // Compiling in Ubuntu14.04 due to glibc issues.
+        // This should be updates once we have clarity on this issue.
+        ci_utils.docker_run('publish.ubuntu1404_cpu', "build_static_libmxnet ${mxnet_variant}", false)
+        ci_utils.pack_lib("mxnet_${mxnet_variant}", libmxnet_pipeline.get_stash(mxnet_variant))
+      }
     }
   }
 }
diff --git a/cd/mxnet_lib/mxnet_lib_pipeline.groovy b/cd/mxnet_lib/mxnet_lib_pipeline.groovy
index 0310dd9..5ca1bb1 100644
--- a/cd/mxnet_lib/mxnet_lib_pipeline.groovy
+++ b/cd/mxnet_lib/mxnet_lib_pipeline.groovy
@@ -75,7 +75,9 @@ def get_stash(mxnet_variant) {
 // Returns the (Docker) environment for the given variant
 // The environment corresponds to the docker files in the 'docker' directory
 def get_environment(mxnet_variant) {
-  if (mxnet_variant.startsWith("cu")) {
+  if (mxnet_variant.startsWith("aarch64")) {
+    return "publish.ubuntu1804_aarch64_cpu"
+  } else if (mxnet_variant.startsWith("cu")) {
     // Remove 'mkl' suffix from variant to properly format test environment
     return "ubuntu_gpu_${mxnet_variant.replace('mkl', '')}"
   }
@@ -85,6 +87,9 @@ def get_environment(mxnet_variant) {
 // Returns the variant appropriate jenkins node test in which
 // to run a step
 def get_jenkins_node_label(mxnet_variant) {
+  if (mxnet_variant.startsWith("aarch64")) {
+    return NODE_LINUX_AARCH64_CPU
+  }
   if (mxnet_variant.startsWith('cu')) {
     return NODE_LINUX_GPU
   }
@@ -105,9 +110,9 @@ def unittest_py3(mxnet_variant) {
   }
 }
 
-// Tests quantization in P3 instance using Python 3
+// Tests quantization in G4 instance using Python 3
 def test_gpu_quantization_py3(mxnet_variant) {
-  node(NODE_LINUX_GPU_P3) {
+  node(NODE_LINUX_GPU_G4) {
     ws("workspace/mxnet_${libtype}/${mxnet_variant}/${env.BUILD_NUMBER}") {
       def image = get_environment(mxnet_variant)
       ci_utils.unpack_and_init("mxnet_${mxnet_variant}", get_stash(mxnet_variant), false)
diff --git a/cd/python/docker/Dockerfile b/cd/python/docker/Dockerfile
index 004a0a9..71eca4a 100644
--- a/cd/python/docker/Dockerfile
+++ b/cd/python/docker/Dockerfile
@@ -32,7 +32,10 @@ RUN apt-get update && \
     wget -nv https://bootstrap.pypa.io/get-pip.py && \
     python3 get-pip.py
 
-RUN apt-get install -y libgomp1 libquadmath0
+RUN apt-get install -y libgomp1
+
+ARG MXNET_VARIANT
+RUN if [ "$MXNET_VARIANT" = "aarch64_cpu" ] ; then echo "not installing libquadmath0 on aarch64" ; else apt-get install -y libquadmath0 ; fi
 
 ARG MXNET_COMMIT_ID
 ENV MXNET_COMMIT_ID=${MXNET_COMMIT_ID}
diff --git a/cd/python/docker/Dockerfile.test b/cd/python/docker/Dockerfile.test
index 3349e93..ebf913b 100644
--- a/cd/python/docker/Dockerfile.test
+++ b/cd/python/docker/Dockerfile.test
@@ -26,11 +26,13 @@ FROM ${BASE_IMAGE}
 ARG USER_ID=1001
 ARG GROUP_ID=1001
 
-COPY ./docker/install/ubuntu_adduser.sh /work/ubuntu_adduser.sh
-COPY ./docker/install/requirements /work/requirements
-
 RUN mkdir -p /work
+
+COPY ./docker/install/ubuntu_adduser.sh /work/ubuntu_adduser.sh
 RUN /work/ubuntu_adduser.sh
+
+ARG REQUIREMENTS_FILE
+COPY ${REQUIREMENTS_FILE} /work/requirements
 RUN pip install -r /work/requirements
 
 WORKDIR /work/mxnet
diff --git a/cd/python/docker/Jenkins_pipeline.groovy b/cd/python/docker/Jenkins_pipeline.groovy
index 2911a65..bf3df36 100644
--- a/cd/python/docker/Jenkins_pipeline.groovy
+++ b/cd/python/docker/Jenkins_pipeline.groovy
@@ -23,17 +23,29 @@
 // NOTE: 
 // ci_utils and cd_utils are loaded by the originating Jenkins job, e.g. jenkins/Jenkinsfile_release_job
 
+def get_node(mxnet_variant) {
+  if (mxnet_variant.startsWith('aarch64')) {
+    return NODE_LINUX_AARCH64_CPU
+  }
+  if (mxnet_variant.startsWith('cu')) {
+    return NODE_LINUX_GPU
+  }
+  return NODE_LINUX_CPU
+}
+
 def get_pipeline(mxnet_variant) {
-  def node_type = mxnet_variant.startsWith('cu') ? NODE_LINUX_GPU : NODE_LINUX_CPU
+  def node_type = get_node(mxnet_variant)
   return cd_utils.generic_pipeline(mxnet_variant, this, node_type)
 }
 
 // Returns the (Docker) environment for the given variant
 // The environment corresponds to the docker files in the 'docker' directory
 def get_environment(mxnet_variant) {
-  if (mxnet_variant.startsWith("cu")) {
-    // Remove 'mkl' suffix from variant to properly format test environment
-    return "ubuntu_gpu_${mxnet_variant.replace('mkl', '')}"
+  if (mxnet_variant.startsWith('aarch64')) {
+    return "publish.ubuntu1804_aarch64_cpu"
+  }
+  if (mxnet_variant.startsWith('cu')) {
+    return "ubuntu_gpu_${mxnet_variant}"
   }
   return "ubuntu_cpu"
 }
diff --git a/cd/python/docker/python_images.sh b/cd/python/docker/python_images.sh
index 05ec518..39fd029 100755
--- a/cd/python/docker/python_images.sh
+++ b/cd/python/docker/python_images.sh
@@ -45,7 +45,7 @@ fi
 
 build() {
     # NOTE: Ensure the correct context root is passed in when building - Dockerfile expects ./wheel_build
-    docker build -t "${image_name}" --build-arg BASE_IMAGE="${base_image}" --build-arg MXNET_COMMIT_ID=${GIT_COMMIT} -f ${resources_path}/Dockerfile ./wheel_build
+    docker build -t "${image_name}" --build-arg BASE_IMAGE="${base_image}" --build-arg MXNET_COMMIT_ID=${GIT_COMMIT} --build-arg MXNET_VARIANT=${mxnet_variant} -f ${resources_path}/Dockerfile ./wheel_build
 }
 
 test() {
@@ -54,9 +54,14 @@ test() {
         runtime_param="--runtime=nvidia"
     fi
     local test_image_name="${image_name}_test"
+    if [[ ${mxnet_variant} == "aarch64_cpu" ]]; then
+        requirements_file="./docker/install/requirements_aarch64"
+    else
+        requirements_file="./docker/install/requirements"
+    fi
 
     # Ensure the correct context root is passed in when building - Dockerfile.test expects ci directory
-    docker build -t "${test_image_name}" --build-arg USER_ID=`id -u` --build-arg GROUP_ID=`id -g` --build-arg BASE_IMAGE="${image_name}" -f ${resources_path}/Dockerfile.test ./ci
+    docker build -t "${test_image_name}" --build-arg USER_ID=`id -u` --build-arg GROUP_ID=`id -g` --build-arg BASE_IMAGE="python:nightly_v1.x_aarch64_cpu_py3" --build-arg REQUIREMENTS_FILE=${requirements_file} -f ${resources_path}/Dockerfile.test ./ci
 }
 
 push() {
diff --git a/cd/python/pypi/Jenkins_pipeline.groovy b/cd/python/pypi/Jenkins_pipeline.groovy
index 125eb2c..dfb3018 100644
--- a/cd/python/pypi/Jenkins_pipeline.groovy
+++ b/cd/python/pypi/Jenkins_pipeline.groovy
@@ -29,17 +29,31 @@
 // We only skip the publish step so we can still QA the other variants.
 pypi_releases = []
 
+def get_node(mxnet_variant) {
+  if (mxnet_variant.startsWith('aarch64')) {
+    return NODE_LINUX_AARCH64_CPU
+  }
+  if (mxnet_variant.startsWith('cu')) {
+    return NODE_LINUX_GPU
+  }
+  return NODE_LINUX_CPU
+}
+
 def get_pipeline(mxnet_variant) {
-  def node_type = mxnet_variant.startsWith('cu') ? NODE_LINUX_GPU : NODE_LINUX_CPU
+  def node_type = get_node(mxnet_variant)
   return cd_utils.generic_pipeline(mxnet_variant, this, node_type)
 }
 
+// Returns the (Docker) environment for the given variant
+// The environment corresponds to the docker files in the 'docker' directory
 def get_environment(mxnet_variant) {
-  def environment = "ubuntu_cpu"
+  if (mxnet_variant.startsWith('aarch64')) {
+    return "publish.ubuntu1804_aarch64_cpu"
+  }
   if (mxnet_variant.startsWith('cu')) {
-    environment = "ubuntu_gpu_${mxnet_variant}".replace("mkl", "")
+    return "ubuntu_gpu_${mxnet_variant}"
   }
-  return environment
+  return "ubuntu_cpu"
 }
 
 def build(mxnet_variant) {
diff --git a/cd/utils/docker_tag.sh b/cd/utils/docker_tag.sh
index 48629ad..518817d 100755
--- a/cd/utils/docker_tag.sh
+++ b/cd/utils/docker_tag.sh
@@ -36,6 +36,8 @@ elif [[ ${mxnet_variant} == "native" ]]; then
     tag_suffix="native"
 elif [[ ${mxnet_variant} == cu* ]]; then
     tag_suffix="gpu_${mxnet_variant}"
+elif [[ ${mxnet_variant} == aarch64* ]]; then
+    tag_suffix="aarch64_cpu"
 
 else
     echo "Error: Unrecognized mxnet variant: '${mxnet_variant}'."
diff --git a/cd/utils/mxnet_base_image.sh b/cd/utils/mxnet_base_image.sh
index 1e366af..7233321 100755
--- a/cd/utils/mxnet_base_image.sh
+++ b/cd/utils/mxnet_base_image.sh
@@ -42,6 +42,9 @@ case ${mxnet_variant} in
     native)
     echo "ubuntu:18.04"
     ;;
+    aarch64_cpu)
+    echo "arm64v8/ubuntu:18.04"
+    ;;
     *)
     echo "Error: Unrecognized mxnet-variant: '${mxnet_variant}'"
     exit 1
diff --git a/ci/Jenkinsfile_utils.groovy b/ci/Jenkinsfile_utils.groovy
index 24c280a..3f774f0 100644
--- a/ci/Jenkinsfile_utils.groovy
+++ b/ci/Jenkinsfile_utils.groovy
@@ -242,9 +242,9 @@ def assign_node_labels(args) {
   //    users from just copy&pasting something into an existing Jenkinsfile without
   //    knowing about the limitations.
   NODE_LINUX_CPU = args.linux_cpu
+  NODE_LINUX_AARCH64_CPU = args.linux_aarch64_cpu
   NODE_LINUX_GPU = args.linux_gpu
   NODE_LINUX_GPU_G4 = args.linux_gpu_g4
-  NODE_LINUX_GPU_P3 = args.linux_gpu_p3
   NODE_WINDOWS_CPU = args.windows_cpu
   NODE_WINDOWS_GPU = args.windows_gpu
   NODE_UTILITY = args.utility
diff --git a/cd/python/docker/Dockerfile.test b/ci/docker/install/requirements_aarch64
similarity index 65%
copy from cd/python/docker/Dockerfile.test
copy to ci/docker/install/requirements_aarch64
index 3349e93..c366219 100644
--- a/cd/python/docker/Dockerfile.test
+++ b/ci/docker/install/requirements_aarch64
@@ -1,4 +1,3 @@
-# -*- mode: dockerfile -*-
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -16,21 +15,20 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# Python MXNet Dockerfile
+# build and install are separated so changes to build don't invalidate
+# the whole docker cache for the image
 
-# NOTE: Assumes 'ci' directory is root of the context when building
-
-ARG BASE_IMAGE
-FROM ${BASE_IMAGE}
-
-ARG USER_ID=1001
-ARG GROUP_ID=1001
-
-COPY ./docker/install/ubuntu_adduser.sh /work/ubuntu_adduser.sh
-COPY ./docker/install/requirements /work/requirements
-
-RUN mkdir -p /work
-RUN /work/ubuntu_adduser.sh
-RUN pip install -r /work/requirements
-
-WORKDIR /work/mxnet
+boto3==1.9.229
+cpplint==1.3.0
+Cython
+decorator==4.4.0
+mock==2.0.0
+nose==1.3.7
+nose-timer==0.7.3
+numpy
+pylint==2.3.1  # pylint and astroid need to be aligned
+astroid==2.3.3  # pylint and astroid need to be aligned
+requests<2.19.0,>=2.18.4
+scipy
+setuptools
+coverage
diff --git a/python/mxnet/test_utils.py b/python/mxnet/test_utils.py
index 927d857..3e3ef5d 100755
--- a/python/mxnet/test_utils.py
+++ b/python/mxnet/test_utils.py
@@ -2551,6 +2551,11 @@ def is_cd_run():
     return os.environ.get("CD_JOB", 0) == "1"
 
 
+def is_aarch64_run():
+    """Checks if the test is running on aarch64 instance"""
+    return platform.machine() == "aarch64"
+
+
 _features = Features()
 
 
diff --git a/tests/python/unittest/test_contrib_operator.py b/tests/python/unittest/test_contrib_operator.py
index 476dfac..758331a 100644
--- a/tests/python/unittest/test_contrib_operator.py
+++ b/tests/python/unittest/test_contrib_operator.py
@@ -268,6 +268,7 @@ def test_bipartite_matching_op():
     assert_match([[0.5, 0.6], [0.1, 0.2], [0.3, 0.4]], [1, -1, 0], [2, 0], 1e-12, False)
     assert_match([[0.5, 0.6], [0.1, 0.2], [0.3, 0.4]], [-1, 0, 1], [1, 2], 100, True)
 
+@unittest.skipIf(is_aarch64_run(), "test fails on aarch64 - tracked in #20289")
 def test_multibox_target_op():
     anchors = mx.nd.array([[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8]], ctx=default_context()).reshape((1, -1, 4))
     cls_pred = mx.nd.array(list(range(10)), ctx=default_context()).reshape((1, -1, 2))
diff --git a/tests/python/unittest/test_ndarray.py b/tests/python/unittest/test_ndarray.py
index c8fbf35..3f93cbe 100644
--- a/tests/python/unittest/test_ndarray.py
+++ b/tests/python/unittest/test_ndarray.py
@@ -31,11 +31,13 @@ from mxnet.test_utils import default_context
 from mxnet.test_utils import np_reduce
 from mxnet.test_utils import same
 from mxnet.test_utils import random_sample, rand_shape_nd, random_arrays
+from mxnet.test_utils import is_aarch64_run
 from mxnet import runtime
 from numpy.testing import assert_allclose, assert_array_equal, assert_array_almost_equal
 import mxnet.autograd
 from mxnet.base import integer_types
 from mxnet.ndarray.ndarray import py_slice
+import unittest
 
 
 def check_with_uniform(uf, arg_shapes, dim=None, npuf=None, rmin=-10, type_list=[np.float32]):
@@ -1283,6 +1285,7 @@ def test_output():
 
 
 @with_seed()
+@unittest.skipIf(is_aarch64_run(), "test fails on aarch64 - tracked in #20289")
 def test_ndarray_fluent():
     has_grad = set(['flatten', 'expand_dims', 'flip', 'tile', 'transpose', 'sum', 'nansum', 'prod',
                     'nanprod', 'mean', 'max', 'min', 'reshape', 'broadcast_to', 'split', 'split_v2',
diff --git a/tests/python/unittest/test_numpy_interoperability.py b/tests/python/unittest/test_numpy_interoperability.py
index fd8abf1..63e74c7 100644
--- a/tests/python/unittest/test_numpy_interoperability.py
+++ b/tests/python/unittest/test_numpy_interoperability.py
@@ -28,6 +28,7 @@ from mxnet import np
 from mxnet.test_utils import assert_almost_equal
 from mxnet.test_utils import use_np
 from mxnet.test_utils import is_op_runnable
+from mxnet.test_utils import is_aarch64_run
 from common import assertRaises, with_seed, random_seed, setup_module, teardown
 from mxnet.numpy_dispatch_protocol import with_array_function_protocol, with_array_ufunc_protocol
 from mxnet.numpy_dispatch_protocol import _NUMPY_ARRAY_FUNCTION_LIST, _NUMPY_ARRAY_UFUNC_LIST
@@ -3066,6 +3067,7 @@ def test_np_memory_array_function():
 
 @with_seed()
 @use_np
+@unittest.skipIf(is_aarch64_run(), "test fails on aarch64 - tracked in #20289")
 @with_array_function_protocol
 def test_np_array_function_protocol():
     check_interoperability(_NUMPY_ARRAY_FUNCTION_LIST)
diff --git a/tests/python/unittest/test_numpy_op.py b/tests/python/unittest/test_numpy_op.py
index 4bdaf52..8b6fc68 100644
--- a/tests/python/unittest/test_numpy_op.py
+++ b/tests/python/unittest/test_numpy_op.py
@@ -34,6 +34,7 @@ from mxnet.test_utils import same, assert_almost_equal, rand_shape_nd, rand_ndar
 from mxnet.test_utils import check_numeric_gradient, use_np, collapse_sum_like, effective_dtype
 from mxnet.test_utils import new_matrix_with_real_eigvals_nd
 from mxnet.test_utils import new_sym_matrix_with_real_eigvals_nd
+from mxnet.test_utils import is_aarch64_run
 from common import assertRaises, with_seed
 import random
 from mxnet.test_utils import verify_generator, gen_buckets_probs_with_ppf
@@ -3573,6 +3574,7 @@ def test_np_swapaxes():
 
 @with_seed()
 @use_np
+@unittest.skipIf(is_aarch64_run(), "test fails on aarch64 - tracked in #20289")
 def test_np_delete():
     class TestDelete(HybridBlock):
         def __init__(self, obj, axis=None):
diff --git a/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md b/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md
new file mode 100644
index 0000000..a84f29d
--- /dev/null
+++ b/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md
@@ -0,0 +1,45 @@
+<!--- Licensed to the Apache Software Foundation (ASF) under one -->
+<!--- or more contributor license agreements.  See the NOTICE file -->
+<!--- distributed with this work for additional information -->
+<!--- regarding copyright ownership.  The ASF licenses this file -->
+<!--- to you under the Apache License, Version 2.0 (the -->
+<!--- "License"); you may not use this file except in compliance -->
+<!--- with the License.  You may obtain a copy of the License at -->
+
+<!---   http://www.apache.org/licenses/LICENSE-2.0 -->
+
+<!--- Unless required by applicable law or agreed to in writing, -->
+<!--- software distributed under the License is distributed on an -->
+<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
+<!--- KIND, either express or implied.  See the License for the -->
+<!--- specific language governing permissions and limitations -->
+<!--- under the License. -->
+
+Prerequisites
+-------------
+This package supports Linux, Mac OSX, and Windows platforms. You may also want to check:
+
+- [mxnet](https://pypi.python.org/pypi/mxnet/).
+- [mxnet-cu112](https://pypi.python.org/pypi/mxnet-cu112/) with CUDA-11.2 support.
+- [mxnet-cu110](https://pypi.python.org/pypi/mxnet-cu110/) with CUDA-11.0 support.
+- [mxnet-cu102](https://pypi.python.org/pypi/mxnet-cu102/) with CUDA-10.2 support.
+- [mxnet-cu101](https://pypi.python.org/pypi/mxnet-cu101/) with CUDA-10.1 support.
+- [mxnet-cu100](https://pypi.python.org/pypi/mxnet-cu100/) with CUDA-10.0 support.
+- [mxnet-native](https://pypi.python.org/pypi/mxnet-native/) CPU variant without MKLDNN.
+
+To use this package on Linux you need the `libquadmath.so.0` shared library. On
+Debian based systems, including Ubuntu, run `sudo apt install libquadmath0` to
+install the shared library. On RHEL based systems, including CentOS, run `sudo
+yum install libquadmath` to install the shared library. As `libquadmath.so.0` is
+a GPL library and MXNet part of the Apache Software Foundation, MXNet must not
+redistribute `libquadmath.so.0` as part of the Pypi package and users must
+manually install it.
+
+To install for other platforms (e.g. Windows, Raspberry Pi/ARM) or other versions, check [Installing MXNet](https://mxnet.apache.org/versions/master) for instructions on building from source.
+
+Installation
+------------
+To install, use:
+```bash
+pip install mxnet
+```
diff --git a/tools/pip/setup.py b/tools/pip/setup.py
index f84d81d..bd18f1e 100644
--- a/tools/pip/setup.py
+++ b/tools/pip/setup.py
@@ -127,7 +127,7 @@ shutil.copy(os.path.join(CURRENT_DIR, 'mxnet-build/src/lib_api.cc'),
 package_name = 'mxnet'
 
 variant = os.environ['mxnet_variant'].upper()
-if variant != 'CPU':
+if not variant.endswith('CPU'):
     package_name = 'mxnet_{0}'.format(variant.lower())
 
 def skip_markdown_comments(md):
@@ -145,7 +145,7 @@ with open('doc/{0}_ADDITIONAL.md'.format(variant)) as variant_doc:
 
 short_description = 'Apache MXNet is an ultra-scalable deep learning framework.'
 libraries = []
-if variant == 'CPU':
+if variant.endswith('CPU'):
     libraries.append('openblas')
 else:
     if variant.startswith('CU112'):
diff --git a/tools/staticbuild/build_lib_cmake.sh b/tools/staticbuild/build_lib_cmake.sh
index 04044bd..ade6b7a 100755
--- a/tools/staticbuild/build_lib_cmake.sh
+++ b/tools/staticbuild/build_lib_cmake.sh
@@ -20,11 +20,7 @@
 set -eo pipefail
 
 # This script builds the libraries of mxnet.
-if [[ $ARCH == 'aarch64' ]]; then
-    cmake_config=${CURDIR}/config/distribution/${PLATFORM}_${ARCH}_${VARIANT}.cmake
-else
-    cmake_config=${CURDIR}/config/distribution/${PLATFORM}_${VARIANT}.cmake
-fi
+cmake_config=${CURDIR}/config/distribution/${PLATFORM}_${VARIANT}.cmake
 
 if [[ ! -f $cmake_config ]]; then
     >&2 echo "Couldn't find cmake config $make_config for the current settings."