如何在 Amazon EMR、EC2 上为 Breeze 配置高性能 BLAS/LAPACK

How to configure high performance BLAS/LAPACK for Breeze on Amazon EMR, EC2

我正在尝试建立一个环境来支持集群上的探索性数据分析。根据对现有内容的初步调查,我的目标是使用 Scala/Spark 和 Amazon EMR 来配置集群。

目前,我只是在尝试获取一些基本示例,并 运行 验证我是否已正确配置所有内容。我遇到的问题是我没有看到我期望从 Amazon 机器实例上的 Atlas BLAS 库获得的性能。

下面是我的简单基准测试的代码片段。它只是一个方阵乘法,然后是短胖乘法和高细乘法,以产生一个可以打印的小矩阵(我想确保 Scala 不会由于惰性评估而跳过计算的任何部分)。

我正在使用 Breeze 作为线性代数库,并使用 netlib-java 为 BLAS/LAPACK

引入本地本地库
import breeze.linalg.{DenseMatrix, DenseVector}
import org.apache.spark.annotation.DeveloperApi
import org.apache.spark.rdd.RDD
import org.apache.spark.{Partition, SparkContext, TaskContext}
import org.apache.spark.SparkConf

import com.github.fommil.netlib.BLAS.{getInstance => blas}

import scala.reflect.ClassTag

object App {

  def NaiveMultiplication(n: Int) : Unit = {

    val vl = java.text.NumberFormat.getIntegerInstance.format(n)
    println(f"Naive Multipication with vector length " + vl)

    println(blas.getClass().getName())

    val sm: DenseMatrix[Double] = DenseMatrix.rand(n, n)
    val a: DenseMatrix[Double] = DenseMatrix.rand(2,n)
    val b: DenseMatrix[Double] = DenseMatrix.rand(n,3)

    val c: DenseMatrix[Double] = sm * sm
    val cNormal: DenseMatrix[Double] = (a *  c)  * b

    println(s"Dot product of a and b is \n$cNormal")
  }

根据对基准测试的网络调查,我预计 3000x3000 矩阵乘法大约需要。 2-4 秒,使用原生的、优化的 BLAS 库。当我 运行 在本地 MacBook Air 上时,此基准测试在 1.8 秒内完成。当我在 EMR 上 运行 它完成大约。 11 秒(使用 g2.2xlarge 实例,尽管在 m3.xlarge 实例上获得了类似的结果)。作为另一个交叉检查,我 运行 来自 BIDMach project 的预构建 EC2 AMI 在相同的 EC2 实例类型 g2.2xlarge 上得到了 2.2s(注意,相同计算的 GPU 基准测试产生了 0.047s) .

在这一点上,我怀疑 netlib-java 没有加载正确的库,但这就是我卡住的地方。我已经阅读了很多 netlib-java 自述文件 times,似乎 ATLAS 库已按要求安装(见下文)

[hadoop@ip-172-31-3-69 ~]$ ls /usr/lib64/atlas/
libatlas.a       libcblas.a       libclapack.so      libf77blas.so      liblapack.so      libptcblas.so      libptf77blas.so
libatlas.so      libcblas.so      libclapack.so.3    libf77blas.so.3    liblapack.so.3    libptcblas.so.3    libptf77blas.so.3
libatlas.so.3    libcblas.so.3    libclapack.so.3.0  libf77blas.so.3.0  liblapack.so.3.0  libptcblas.so.3.0  libptf77blas.so.3.0
libatlas.so.3.0  libcblas.so.3.0  libf77blas.a       liblapack.a        libptcblas.a      libptf77blas.a
[hadoop@ip-172-31-3-69 ~]$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
[hadoop@ip-172-31-3-69 ~]$ ls /etc/ld.so.conf.d
atlas-x86_64.conf  kernel-4.4.11-23.53.amzn1.x86_64.conf  kernel-4.4.8-20.46.amzn1.x86_64.conf  mysql55-x86_64.conf  R-x86_64.conf
[hadoop@ip-172-31-3-69 ~]$ cat /etc/ld.so.conf.d/atlas-x86_64.conf 
/usr/lib64/atlas

下面我展示了 2 个示例 运行在 Amazon EMR 实例上进行基准测试。第一个显示本机系统 BLAS 应该正确加载的时间。第二个显示本机 BLAS 未加载且包回退到参考实现的时间。因此,它似乎确实正在根据消息和时间加载本机 BLAS。与我的 Mac 本地 运行ning 相比,无 BLAS 案例 运行s 大约在同一时间,但原生 BLAS 案例 运行s 在我的 [=1.8s 内=45=] 与下面案例中的 15s 相比。与 EMR 相比,我的 Mac 的信息消息是相同的(除了特定的 dir/file 名称等)。

[hadoop@ip-172-31-3-69 ~]$ spark-submit --class "com.cyberatomics.simplespark.App" --conf "spark.driver.extraClassPath=/home/hadoop/simplespark-0.0.1-SNAPSHOT-jar-with-dependencies.jar"   --master local[4] simplespark-0.0.1-SNAPSHOT-jar-with-dependencies.jar  3000 naive
Naive Multipication with vector length 3,000
Jun 16, 2016 12:30:39 AM com.github.fommil.jni.JniLoader liberalLoad
INFO: successfully loaded /tmp/jniloader2856061049061057802netlib-native_system-linux-x86_64.so
com.github.fommil.netlib.NativeSystemBLAS
Dot product of a and b is 
1.677332076284315E9   1.6768329748988206E9  1.692150656424957E9   
1.6999000993276503E9  1.6993872020220244E9  1.7149145239563465E9  
Elapsed run time:  15.1s
[hadoop@ip-172-31-3-69 ~]$ 
[hadoop@ip-172-31-3-69 ~]$ spark-submit --class "com.cyberatomics.simplespark.App"  --master local[4] simplespark-0.0.1-SNAPSHOT-jar-with-dependencies.jar  3000 naive
Naive Multipication with vector length 3,000
Jun 16, 2016 12:31:32 AM com.github.fommil.netlib.BLAS <clinit>
WARNING: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS
Jun 16, 2016 12:31:32 AM com.github.fommil.netlib.BLAS <clinit>
WARNING: Failed to load implementation from: com.github.fommil.netlib.NativeRefBLAS
com.github.fommil.netlib.F2jBLAS
Dot product of a and b is 
1.6640545115052865E9  1.6814609592261212E9  1.7062846398842275E9  
1.64471099826913E9    1.6619129531594608E9  1.6864479674870768E9  
Elapsed run time:  28.7s

在这一点上,我最好的猜测是它实际上正在加载一个本地库,但它正在加载一个通用库。关于如何验证它在 运行 时间获取哪个共享库的任何建议?我试过 'ldd' 但这似乎不适用于 spark-submit。或者也许我对 Atlas 的期望是错误的,但似乎很难相信 AWS 会预装这些库,如果它们没有运行具有合理竞争力的速度。

如果您发现这些库在 EMR 上没有正确链接,请提供指导,说明我需要做什么才能让 Netlib 获取 Atlas 库-java.

谢谢 蒂姆

跟进:

我的初步结论是,Amazon EMR 实例上默认安装的 Atlas 库非常慢。它要么是未针对特定机器类型进行优化的通用构建,要么从根本上比其他库慢。使用这个 script as a guide I built and installed OpenBLAS for the specific machine type where I was running the benchmarks(I also found some helpful info here)。安装 OpenBLAS 后,我的 3000x3000 矩阵乘法基准测试在 3.9 秒内完成(与上面列出的使用默认 Atlas 库时的 15.1 秒相比)。这仍然比我的 Mac 上的相同基准 运行 慢(x2 倍),但这种差异落在一个范围内,这可能是由于潜在的 h/w 性能所致。

这是我用来在 Amazon 的 EMR、Spark 实例上安装 OpenBLAS 库的命令的完整列表:

sudo yum install git
git clone https://github.com/xianyi/OpenBlas.git
cd OpenBlas/
make clean
make -j4
sudo mkdir /usr/lib64/OpenBLAS
sudo chmod o+w,g+w /usr/lib64/OpenBLAS/
make PREFIX=/usr/lib64/OpenBLAS install
sudo rm /etc/ld.so.conf.d/atlas-x86_64.conf 
sudo ldconfig
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/libblas.so
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/libblas.so.3
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/libblas.so.3.5
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/liblapack.so
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/liblapack.so.3
sudo ln -sf /usr/lib64/OpenBLAS/lib/libopenblas.so /usr/lib64/liblapack.so.3.5