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

[incubator-mxnet] branch v1.9.x updated: [v1.9.x] aarch64 build using gcc8.5 + APL integration + CD pipeline (#20333)

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

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


The following commit(s) were added to refs/heads/v1.9.x by this push:
     new 7e3bd45  [v1.9.x] aarch64 build using gcc8.5 + APL integration + CD pipeline (#20333)
7e3bd45 is described below

commit 7e3bd453309bffb9808286d7cb5be52c6a91f43a
Author: waytrue17 <52...@users.noreply.github.com>
AuthorDate: Fri Jun 4 17:16:24 2021 -0700

    [v1.9.x] aarch64 build using gcc8.5 + APL integration + CD pipeline (#20333)
    
    * [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
    
    * [v1.x] Enable MKLDNN + APL Integration in CD (#20294)
    
    * initial
    
    * Update python_images.sh
    
    * Update python_images.sh
    
    * Update Dockerfile
    
    * Update Dockerfile
    
    * Update Dockerfile
    
    * Update AARCH64_CPU_ADDITIONAL.md
    
    * Update pip.md
    
    * Update pip.md
    
    * [v1.x] use gcc-8.5 instead of gcc-10 for aarch64 build (#20318)
    
    * use gcc-8.5 instead of gcc-10 with outline-atomics flag
    
    * debug openblas
    
    * fix apt install
    
    * use gcc-7 for openblas
    
    * use gcc-8.4 for openblas
    
    * update openblas
    
    * remove gcc-8 as no longer required
    
    * [v1.x] Update openblas version to 0.3.15 (#20328)
    
    * update apl version
    
    Co-authored-by: Manu Seth <22...@users.noreply.github.com>
    Co-authored-by: Zhaoqi Zhu <zh...@gmail.com>
    Co-authored-by: Wei Chu <we...@amazon.com>
---
 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                        | 11 ++++-
 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 +-
 .../Dockerfile.publish.ubuntu1804_aarch64_cpu      |  3 ++
 .../docker/install/requirements_aarch64            | 34 ++++++++--------
 ci/docker/install/ubuntu_aarch64_publish.sh        | 26 +++++++++---
 config/distribution/linux_aarch64_cpu.cmake        |  4 +-
 .../_includes/get_started/linux/python/cpu/pip.md  |  6 +++
 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/dependencies/openblas.sh                     |  8 +++-
 tools/pip/doc/AARCH64_CPU_ADDITIONAL.md            | 47 ++++++++++++++++++++++
 tools/pip/setup.py                                 |  4 +-
 tools/staticbuild/build_lib_cmake.sh               |  6 +--
 26 files changed, 208 insertions(+), 62 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..cbfd9e6 100644
--- a/cd/python/docker/Dockerfile
+++ b/cd/python/docker/Dockerfile
@@ -32,7 +32,16 @@ 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
+RUN if [ "$MXNET_VARIANT" = "aarch64_cpu" ] ; \
+    then wget https://armkeil.blob.core.windows.net/developer/Files/downloads/hpc/arm-performance-libraries/21-0-0/Ubuntu18.04/arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2.tar && \
+    tar -xvf arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2.tar && \
+    arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2/arm-performance-libraries_21.0_Ubuntu-18.04.sh -a; \
+    fi
+ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/opt/arm/armpl_21.0_gcc-8.2/lib
 
 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..41bf0d2 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="${image_name}" --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/ci/docker/Dockerfile.publish.ubuntu1804_aarch64_cpu b/ci/docker/Dockerfile.publish.ubuntu1804_aarch64_cpu
index 6b2db8a..129984c 100644
--- a/ci/docker/Dockerfile.publish.ubuntu1804_aarch64_cpu
+++ b/ci/docker/Dockerfile.publish.ubuntu1804_aarch64_cpu
@@ -24,6 +24,9 @@ WORKDIR /work/deps
 
 COPY install/ubuntu_aarch64_publish.sh /work/
 RUN /work/ubuntu_aarch64_publish.sh
+ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/opt/arm/armpl_21.0_gcc-8.2/lib
+ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/gcc-8.5.0/lib64
+ENV PATH=${PATH}:/usr/local/gcc-8.5.0/bin
 
 ARG USER_ID=0
 ARG GROUP_ID=0
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/ci/docker/install/ubuntu_aarch64_publish.sh b/ci/docker/install/ubuntu_aarch64_publish.sh
index d47755f..7816526 100755
--- a/ci/docker/install/ubuntu_aarch64_publish.sh
+++ b/ci/docker/install/ubuntu_aarch64_publish.sh
@@ -39,6 +39,7 @@ apt-get install -y git \
     gnupg \
     gnupg2 \
     gnupg-agent \
+    libc6-lse \
     pandoc \
     python3 \
     python3-pip \
@@ -47,11 +48,22 @@ apt-get install -y git \
     openjdk-8-jdk \
     patchelf
 
-# gcc-10 required for -moutline-atomics flag
-apt-add-repository "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic main"
-apt-get update
-apt install -y gcc-10 g++-10 gfortran-10
-update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10 --slave /usr/bin/gcov gcov /usr/bin/gcov-10 --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-10
+# build gcc-8.5 from source
+apt update
+apt install -y flex bison
+wget https://ftpmirror.gnu.org/gcc/gcc-8.5.0/gcc-8.5.0.tar.xz
+tar xf gcc-8.5.0.tar.xz
+cd gcc-8.5.0/
+sed -i contrib/download_prerequisites -e '/base_url=/s/ftp/http/'
+contrib/download_prerequisites
+cd ..
+mkdir build && cd build
+../gcc-8.5.0/configure -v --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --prefix=/usr/local/gcc-8.5.0 --enable-checking=release --enable-languages=c,c++,fortran --disable-multilib --program-suffix=-8.5
+make -j$(nproc)
+sudo make install-strip
+cd ..
+rm -rf gcc-8.5.0.tar.xz
+update-alternatives --install /usr/bin/gcc gcc /usr/local/gcc-8.5.0/bin/gcc-8.5 100 --slave /usr/bin/g++ g++ /usr/local/gcc-8.5.0/bin/g++-8.5 --slave /usr/bin/gcov gcov /usr/local/gcc-8.5.0/bin/gcov-8.5 --slave /usr/bin/gfortran gfortran /usr/local/gcc-8.5.0/bin/gfortran-8.5
 
 curl -o apache-maven-3.3.9-bin.tar.gz -L http://www.eu.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz \
     || curl -o apache-maven-3.3.9-bin.tar.gz -L https://search.maven.org/remotecontent?filepath=org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.tar.gz
@@ -75,3 +87,7 @@ cd cmake-3.16.5
 make -j$(nproc)
 sudo make install
 
+# Download and set up Arm Performance Libraries
+wget https://armkeil.blob.core.windows.net/developer/Files/downloads/hpc/arm-performance-libraries/21-0-0/Ubuntu18.04/arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2.tar
+tar -xvf arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2.tar
+arm-performance-libraries_21.0_Ubuntu-18.04_gcc-8.2/arm-performance-libraries_21.0_Ubuntu-18.04.sh -a
diff --git a/config/distribution/linux_aarch64_cpu.cmake b/config/distribution/linux_aarch64_cpu.cmake
index 391d341..f413451 100644
--- a/config/distribution/linux_aarch64_cpu.cmake
+++ b/config/distribution/linux_aarch64_cpu.cmake
@@ -16,7 +16,7 @@
 # under the License.
 
 set(CMAKE_BUILD_TYPE "Distribution" CACHE STRING "Build type")
-set(CFLAGS "-march=armv8-a" CACHE STRING "CFLAGS")
+set(CFLAGS "-march=armv8-a+crc+crypto -moutline-atomics" CACHE STRING "CFLAGS")
 set(CXXFLAGS "-march=armv8-a" CACHE STRING "CXXFLAGS")
 
 set(USE_CUDA OFF CACHE BOOL "Build with CUDA support")
@@ -39,4 +39,4 @@ set(ENV{ACL_ROOT_DIR} "")
 set(MKLDNN_USE_ACL OFF CACHE BOOL "Integrate MKLDNN with Arm Compute Library")
 # APL can be downloaded from https://developer.arm.com/tools-and-software/server-and-hpc/downloads/arm-performance-libraries
 # Note that APL needs to be added to LD_LIBRARY_PATH
-set(MKLDNN_USE_APL OFF CACHE BOOL "Integrate MKLDNN with Arm Performance Libraries")
+set(MKLDNN_USE_APL ON CACHE BOOL "Integrate MKLDNN with Arm Performance Libraries")
diff --git a/docs/static_site/src/_includes/get_started/linux/python/cpu/pip.md b/docs/static_site/src/_includes/get_started/linux/python/cpu/pip.md
index e8363b7..35d8e75 100644
--- a/docs/static_site/src/_includes/get_started/linux/python/cpu/pip.md
+++ b/docs/static_site/src/_includes/get_started/linux/python/cpu/pip.md
@@ -55,6 +55,12 @@ Graphics and Xe architecture-based Graphics. Support for other architectures
 such as Arm* 64-bit Architecture (AArch64) and OpenPOWER* Power ISA (PPC64) is
 experimental.
 
+Please note that the Linux CPU pip wheels for AArch64 platforms are built with
+oneDNN with Arm Performance Libraries (APL) integrated. Because APL's license
+is not compatible with Apache license, you would need to
+<a href="https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries">manually install</a> APL
+in your system.
+
 oneDNN is intended for deep learning applications and framework developers
 interested in improving application performance on Intel CPUs and GPUs, more
 details can be found <a href="https://github.com/oneapi-src/oneDNN">here</a>.
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/dependencies/openblas.sh b/tools/dependencies/openblas.sh
index 8871d04..17714ce 100755
--- a/tools/dependencies/openblas.sh
+++ b/tools/dependencies/openblas.sh
@@ -19,7 +19,7 @@
 
 # This script builds the static library of openblas that can be used as dependency of mxnet.
 set -ex
-OPENBLAS_VERSION=0.3.7
+OPENBLAS_VERSION=0.3.13
 if [[ ((! -e $DEPS_PATH/lib/libopenblas.a) && -z "$CMAKE_STATICBUILD") ||
           ((! -e $DEPS_PATH/lib/libopenblas.so) && -v CMAKE_STATICBUILD) ]]; then
     # download and build openblas
@@ -33,7 +33,11 @@ if [[ ((! -e $DEPS_PATH/lib/libopenblas.a) && -z "$CMAKE_STATICBUILD") ||
     cd $DEPS_PATH/OpenBLAS-$OPENBLAS_VERSION
 
     # Adding NO_DYNAMIC=1 flag causes make install to fail
-    CXX="g++ -fPIC" CC="gcc -fPIC" $MAKE DYNAMIC_ARCH=1 USE_OPENMP=1
+    if [[ ! $ARCH == 'aarch64' ]]; then
+        CXX="g++ -fPIC" CC="gcc -fPIC" $MAKE DYNAMIC_ARCH=1 USE_OPENMP=1
+    else
+        $MAKE DYNAMIC_ARCH=1 USE_OPENMP=1
+    fi
 
     if [[ -v CMAKE_STATICBUILD ]]; then
         # We link and redistribute libopenblas.so for cmake staticbuild
diff --git a/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md b/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md
new file mode 100644
index 0000000..bedca05
--- /dev/null
+++ b/tools/pip/doc/AARCH64_CPU_ADDITIONAL.md
@@ -0,0 +1,47 @@
+<!--- 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.
+
+Please also note that the `AArch64` wheels are built with MKLDNN, and MKLDNN in turn is integrated with [Arm Performance Libraries (APL)](https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries). Because APL's license is also not compatible with Apache, users must manually install APL in their system.
+
+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."