Skip to main content
 首页 » 编程设计

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

2024年10月25日41Renyi-Fan

我正在尝试设置一个环境来支持集群上的探索性数据分析。根据对现有情况的初步调查,我的目标是使用 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-4s 使用原生的、优化的 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 README 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 实例上运行基准测试的示例。第一个显示 native 系统 BLAS 应该何时正确加载。第二个显示 native BLAS 未加载并且包回退到引用实现的时间。因此,它似乎确实在根据消息和时间加载 native BLAS。与在我的 Mac 上本地运行相比,无 BLAS 案例的运行时间大致相同,但 native BLAS 案例在我的 Mac 上运行时间为 1.8 秒,而在下面的案例中为 15 秒。与 EMR 相比,我的 Mac 的信息消息是相同的(特定目录/文件名等除外)。
[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-java 获取 Atlas 库。

谢谢
蒂姆

请您参考如下方法:

跟进:

我的初步结论是 Amazon EMR 实例上默认安装的 Atlas 库很慢。它要么是尚未针对特定机器类型进行优化的通用构建,要么从根本上比其他库慢。使用此 script作为指南,我为运行基准测试的特定机器类型构建并安装了 OpenBLAS(我还找到了一些有用的信息 here)。安装 OpenBLAS 后,我的 3000x3000 矩阵乘法基准测试在 3.9 秒内完成(与使用默认 Atlas 库时上面列出的 15.1 秒相比)。这仍然比在我的 Mac 上运行的相同基准测试慢(x2 倍),但这种差异落在一个范围内,这可能是由于潜在的硬件性能。

这是我用于在 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