雲上 ARM 實例應用優化之我見

ARM 處理器的崛起

過去兩個月的科技媒體上關於ARM 芯片的新聞可謂是高潮迭起,不斷的引起人們的關注。

  • 首先是在5月11日,AWS宣佈了基於自研的Graviton 2處理器(使用了ARM Neoverse N1核心)的第六代EC2實例 – M6g正式發佈。這似乎揭開了雲計算市場上ARM處理器大規模應用的的序幕。
  • 緊接着,在今年6月23日的WWDC大會上,Apple公司宣佈了一個影響深遠的決定: 計劃從2020年年底開始,Mac計算機將會從Intel芯片過渡到使用基於ARM的自研芯片。也許我們要問,ARM 處理器將將會在桌面設備上覆制移動設備的成功嗎?
  • 第三則新聞是關於高性能計算。6月22日發表的最新的一期TOP500榜單上,日本的 Fugaku系統以415.5千萬億次浮點運算的高性能LINPAC成績成爲TOP500 的第一名。而令人驚訝的是這是第一個使用ARM處理器的高性能處理系統。

林林總總,即使我們是半導體行業的門外漢也不難得出一個結論 – ARM 處理器不僅僅統治了手機、嵌入式應用這些傳統的優勢領域,或將在桌面系統、高性能計算尤其是雲計算領域扮演越來越重要的角色。

EC2 上的ARM 處理器

以往我們熟悉的AWS所提供的的計算資源所使用的多爲Intel® Xeon® 處理器,例如Skylake 、Ivy Bridge、Broadwell以及Haswell等Intel的多個系列的CPU。即使在2018年新出現的使用了AMD EPYC 處理器的新的實例類型(M5a、R5a以及T3a等),其CPU的架構體系與Intel 的CPU 也還同屬 “x86-64”(也被稱作x64、AMD64以及Intel 64等)體系架構。拋開Intel 與AMD半世紀的愛恨情仇,我們可以簡單的把這些處理器視作一類。

而這一次M6g 實例上的處理器卻與以往大有不同,採用的是一款名爲Graviton 2 處理器,是由 AWS 使用 64 位 ARM Neoverse N1 內核定製而成。說起ARM處理器,我們所瞭解的是其在移動計算市場的所向披靡,卻一直在桌面計算、服務器等對性能要求更高的市場中表現不佳。在過去數年中,ARM不止一次對高性能處理器領域發起挑戰,但多以慘淡的結果收場。而轉機就出現在2019年初ARM發表的Neoverse N1。對於這一次的發佈,ARM的設計目標就是使其成爲一個高性能架構,並重新調校了微架構使其能夠以更高的頻率運行。在這一點上,ARM與AMD、Intel的路線有所不同,後兩家面向高性能平臺的處理器產品受制於功耗、面積等因素,頻率相比消費級產品要低。但是在N1的設計中卻恰好相反,處理器的頻率相對更高。不僅如此,Neoverse N1還有一些獨特設計,例如緩存的設計。N1中的L1數據緩存和指令緩存部分都是64KB、4-Way設計。其中最重要的改變是整個緩存完全採用了一致性設計,它大幅度簡化了虛擬環境的實現並且極大地提高了性能。而且這一設計對ARM在超大規模計算中保持競爭力也是必須的,因爲這可以很方便地擴展核心數量。而這一點在Graviton2 處理器上表現的淋漓盡致。與第一代 AWS Graviton 處理器相比,Graviton2 處理器實現了性能和功能飛躍,性能提升 7 倍、計算內核數量增加 4 倍,緩存增加 2 倍,內存速度提升 5 倍。

總體來看,Graviton 2 與N1平臺差異不大,且採用了TSMC的7nm工藝。當然細微差異還是存在的。例如Graviton 2的CPU內核的時鐘頻率較N1要低一些。我自己運行一個簡單的測試程序得到的Gravitino 2 時鐘頻率約爲2.5GHz,並且L3緩存爲32MB而不是公版的64MB。該系統由8通道DDR-3200內存控制器支持,並且SoC支持64個PCIe4通道用於I/O。至於這款芯片的功耗,考慮到ARM宣稱的64核2.6GHz CPU的功耗約爲105W,以及Ampere最近披露的其80核3GHz N1服務器芯片的功耗爲210W。ANANDTECH 對Graviton 2給出的的估算結果是功耗大致位於80瓦至之110瓦之間。

現代的CPU 存在着核心數量越來越多的趨勢。隨着系統中的核心數量的增多,服務器芯片中的內存性能成爲了影響性能至關重要的因素。藉助8個DDR4-3200內存控制器, Graviton 2芯片具有先進的內存功能,理論上可提供高達204GB/s的峯值帶寬。在ANANDTECH 的測試中, Graviton2的單個CPU內核能夠以高達36GB/s的速度傳輸寫入數據。內存加載速度高達18.3GB/s,內存複製達到了令人印象深刻的29.57GB/s,這是測試中AMD系統的兩倍以上,幾乎是Intel系統的三倍。關於ANANDTECH的這份測試報告,可以訪問這個鏈接來了解 https://www.anandtech.com/print/15578/cloud-clash-amazon-graviton2-arm-against-intel-and-amd

AWS Graviton2處理器的性能

與一年前發佈的第一代 AWS Graviton 處理器相比,Graviton2 處理器不管在性能還是功能上都實現了一次巨大的飛躍。它們都支持 Amazon EC2 M6g、C6g 和 R6g 實例,而且與當前這一代基於 x86 的實例相比,這些實例爲各種工作負載(包括應用程序服務器、微服務、高性能計算、電子設計自動化、遊戲、開源數據庫和內存中的緩存)提供高達 40% 的性價比提升。AWS Graviton2 處理器也爲視頻編碼工作負載提供增強的性能,爲壓縮工作負載提供硬件加速,併爲基於 CPU 的機器學習推理提供支持。它們可以提供高 7 倍的性能、多 4 倍的計算核心、快 5 倍內存和大 2 倍緩存。

在AWS re:Invent 2019大會上,EC2產品團隊分享的幾組處理器Benchmark的結果就讓人興奮不已。

此外,在今年3月份KeyDB分享了它們針對M6g vs M5實例上的性能對比測試。衆所周知,KeyDB是Redis的多線程超集,由於其先進的體系結構,具備了很好的性能表現。

他們的測試結論是這樣的 –

“M5實例使用Intel Xeon Platinum 8175處理器,與其他大多數可用實例類型相比,它們通常爲我們帶來非常好的效果。令我們震驚的是,在較小的使用AWS Graviton2處理器的M6g實例上,與現有的KeyDB M5實例相比,獲得瞭如此巨大的收益。

m6g.large比m5.large快1.65倍,而m6g.xlarge則比m5.xlarge快1.45倍。隨着內核數量的增加,兩種產品之間的差距開始縮小。但是,我們仍在研究m6g.2xlarge和m6g.4xlarge的性能,因爲我們相信可以將性能水平提高到相同的倍數。在此測試中,我們沒有針對M6g進行任何調整,因此我們對即將到來的結果感到樂觀。”

而在今年的5月15日,在測試工具市場久負盛名的Phoronix 發表了一篇關於使用Graviton2 CPU的新M6g 實例的性能測試的文章。他們使用M6g實例作爲基準。然後將這些實例與較早的A1Graviton實例進行比較。在Intel Xeon方面,選擇了M5實例,在AMD EPYC方面選擇的是M5a實例。該測試報告的全文的鏈接在這裏,https://www.phoronix.com/scan.php?page=article&item=amazon-graviton2-benchmarks&num=1

這裏僅僅擷取其中的部分結果以供各位參考:

  1. Linux Kernel(V5.4)的編譯時間,數字越小越好

  2. Memcached mcperf v1.6.0, 數字越大越好

EC2 實例吞吐量的基礎概念 – vCPU 與核心

除了實例類型之外(例如M5、C4),其它用於描述實例能力的最重要的指標就是其vCPU的數量。所謂的vCPU是Virtual Central Processing Units 的縮寫。vCPU 本質上是指虛擬機上可用的邏輯CPU的內核。但EC2 的邏輯CPU計算方法卻並非是基於物理上的CPU內核。準確的說,併發線程的數量即爲EC2 vCPU的數量。例如,默認情況下,M5.xlarge 實例類型有兩個 CPU 內核,每個內核支持兩邏輯個線程,這樣該類型實例的vCPU的數量即爲4個。EC2實例範圍通常從1個vCPU到最多128個,常見的實例的vCPU的數量多爲2、4、8、16、32、48、64和96等。

Graviton 2是不帶SMT的單路64核平臺。所謂的SMT(Simultaneous multithreading) 的含義其實就是我們熟知的超線程技術。簡單來說,SMT技術可以在一個實體CPU中提供兩個邏輯線程,通過分享處理器的資源來提高性能。在Intel 的CPU中類似的技術被稱作Hyper-Threading,或者簡稱HT。目前,Graviton 2 最大可用vCPU實例大小爲就是64。

但是,這也意味着在談論例如64個vCPU 實例的時候(在EC2中的規格稱爲16xlarge),對於Graviton2實例我們將獲得64個物理核心,而對於AMD或Intel系統,我們將僅獲得32個具有SMT的物理核心。這確實有一點“不公平”的味道,但是考慮到規格描述的一致性,這一點差別只好被忽略了。

ARM 實例的應用優化

Graviton 2目前被用於EC2 家族中的M6g、C6g以及R6g實例。其中,

  • M6g實例用於具有CPU、內存和網絡資源平衡的通用工作負載
  • C6g 實例用於計算優化的工作負載,例如視頻編碼、建模和遊戲服務器
  • R6g實例用於內存優化的工作負載,可處理內存中的大型數據集(如數據庫)

與我們熟悉的型x86-64 架構不同,Graviton 2支持ARM V8.2和其它幾個架構擴展。特別要強調的是,Graviton2支持 用於原子操作的LSE (Large System Extension) 指令集的擴展,可以提高大系統之間的鎖定和同步性能。此外,它還支持FP16和用於機器學習的INT8等。毫不誇張的說,這一次Graviton2給我們帶來的足夠的驚喜。但不可否認的是,ARM處理器的體系結構與以往我們所熟悉的x86-64處理器的差異還是非常之大的。簡而言之,如果我們不掌握針對ARM處理器的應用優化的方法,我們所看到的這一切性能上的提升不過是鏡花水月。

C/C++ 代碼在 Graviton 上的優化

C/C ++代碼將極大的受益於設置優化代碼的編譯器標誌並啓用ARM特定的功能。

  • GCC/G++編譯選項

    CPU GCC LLVM
    Graviton -march=armv8-a+crc+crypto -march=armv8-a+crc+crypto
    Graviton 2 -march=armv8.2-a+fp16+rcpc+dotprod+crypto -march=armv8.2-a+fp16+rcpc+dotprod+crypto

    -march 編譯項告訴編譯器應該爲系統的處理器架構生成什麼代碼,即向編譯器聲明應該爲某種CPU架構生成代碼。不同的CPU具有不同的功能,支持不同的指令集,執行代碼的方式也不同。march標誌將指示編譯器爲系統的CPU生成特定的代碼,包括CPU的所有功能、特性、指令集、異常等等。

    ** 需要注意的一點是,對於GCC 7.x和8.1、8.2和8.3 等版本 -march=native不能正確地檢測Graviton 2體系架構。務必請使用-march=armv8.2-a 而不是-march=native。GCC 9.x 以及10.x 則可以很好的識別Graviton 2的體系結構。目前Amazon Linux 2 缺省安裝的GCC版本是7.3.1,而 Ubuntu 20.04 缺省安裝的GCC 版本爲9.3.0,還可以通過sudo apt install gcc-10 安裝 GCC 10.0.1。

    CPU GCC < 9 GCC >= 9
    Graviton -mtune=cortex-a72 -mtune=cortex-a72
    Graviton 2 -mtune=cortex-a72 -mtune=neoverse-n1

    -mtune此選項指定GCC爲其調整代碼性能對應特定目標ARM處理器類型,可以通過使用這個選項來實現更好的性能。此外,此選項可以指定GCC爲big.LITTLE系統調整代碼的性能。

    所謂的big.LITTLE ,是ARM的異質運算多核心處理器技術。具體做法是將比較耗電、但運算能力強的處理器核心組成的“big集羣”與低耗電、運算能力弱的處理器核心組成的“LITTLE集羣”結合在一起,這些處理器核心共享存儲器區段,並能夠在不同的CPU集羣之間在線實時分派、切換負載。

  • Large-System Extensions (LSE)

    Graviton 2處理器支持ARMv8.2指令集。LSE則提供低成本的原子操作。原因是是LSE提高了CPU對CPU的通信、鎖和互斥的系統吞吐量。當使用LSE而不是加載/存儲獨佔時,這種改進可以提升一個數量級。POSIX線程庫需要LSE原子指令。LSE對於鎖定和線程同步例程很重要。例如Amazon Linux 2 與Ubuntu 20.04均發佈了一個支持LSE指令的libc 庫。編譯器需要爲使用原子操作的應用程序生成LSE指令。例如,像PostgreSQL這樣的數據庫代碼包含原子結構;帶有std::原子語句的C++11代碼轉換爲原子操作。GCC的-march=armv8.2-a標誌支持所有由Graviton2支持的指令,包括了LSE。如果需要滿足對於LSE的支持,還需要libc 的版本要高於2.3.0。目前Amazon Linux 2 的glibc 的版本爲2.26, Ubuntu 20.04 的libc 的版本爲2.31。

Java 程序在Graviton 上的優化

Java是一種通用編程語言。 編譯後的Java代碼可以在支持Java的所有平臺上運行,而無需重新編譯。 Java應用程序通常被編譯爲可在任何Java虛擬機(JVM)上運行的字節碼,而與基礎計算機體系結構無關。Java受到了包括ARM在內的廣泛的支持,並且在ARM64上是開箱即用的。 Amazon Corretto是一種免費的,跨平臺的,可立即投入生產的Open Java Development Kit(OpenJDK)發行版,支持由Graviton驅動的實例。如要獲得Amazon Corretto 的安裝包請訪問這個鏈接https://aws.amazon.com/corretto

注意:下載時需要選擇aarh64 的安裝包。

此外,OpenJDK 也提供了對於arm64 平臺的支持。在Graviton 處理器上,可以選擇安裝openjdk-8、openjdk-11、openjdk-13以及openjdk-14 等不同的JDK版本。

Java JAR可以包含特定於體系結構的共享庫。一些Java庫檢查是否找到了這些共享庫,是否使用JNI調用了本機庫,而不是依賴於該函數的通用Java實現。儘管代碼可以工作,但是如果沒有JNI,性能可能會受到影響。

檢查JAR是否包含此類共享庫的一種快速方法是簡單地將其解壓縮,並檢查是否有任何結果文件是共享庫,以及是否缺少aarch64(arm64)共享庫:

$ unzip foo.jar
$ find . -name "*.so" | xargs file

Python程序在Graviton 上的優化

Python 程序解釋執行的特點需要我們使用的Python解釋器可以很好適配於Graviton 處理器。對於Python解釋器優化的關鍵是確保解釋器使用了PGO和LTO等優化編譯的選項。獲得Python 解釋器編譯選項的方法很簡單,

python3 -c “import sysconfig; print(sysconfig.get_config_var(‘CONFIG_ARGS’))”

Amazon Linux 2 Ubuntu 20.03
Python 3.7.6 Python 3.8.2
‘–build=aarch64-koji-linux-gnu’ ‘–host=aarch64-koji-linux-gnu’ ‘–program-prefix=’ ‘–disable-dependency-tracking’ ‘–prefix=/usr’ ‘–exec-prefix=/usr’ ‘–bindir=/usr/bin’ ‘–sbindir=/usr/sbin’ ‘–sysconfdir=/etc’ ‘–datadir=/usr/share’ ‘–includedir=/usr/include’ ‘–libdir=/usr/lib64’ ‘–libexecdir=/usr/libexec’ ‘–localstatedir=/var’ ‘–sharedstatedir=/var/lib’ ‘–mandir=/usr/share/man’ ‘–infodir=/usr/share/info’ ‘–enable-ipv6’ ‘–enable-shared’ ‘–with-computed-gotos=yes’ ‘–with-dbmliborder=gdbm:ndbm:bdb’ ‘–with-system-expat’ ‘–with-system-ffi’ ‘–enable-loadable-sqlite-extensions’ ‘–with-dtrace’ ‘–with-lto’ ‘–with-ssl-default-suites=openssl’ ‘–without-ensurepip’ ‘–enable-optimizations’ ‘build_alias=aarch64-koji-linux-gnu’ ‘host_alias=aarch64-koji-linux-gnu’ ‘CFLAGS=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong –param=ssp-buffer-size=4 -grecord-gcc-switches -D_GNU_SOURCE -fPIC -fwrapv ‘ ‘LDFLAGS=-Wl,-z,relro -g ‘ ‘CPPFLAGS= ‘ ‘PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig’ ‘–enable-shared’ ‘–prefix=/usr’ ‘–enable-ipv6’ ‘–enable-loadable-sqlite-extensions’ ‘–with-dbmliborder=bdb:gdbm’ ‘–with-computed-gotos’ ‘–without-ensurepip’ ‘–with-system-expat’ ‘–with-system-libmpdec’ ‘–with-dtrace’ ‘–with-system-ffi’ ‘CC=aarch64-linux-gnu-gcc’ ‘CFLAGS=-g -fstack-protector-strong -Wformat -Werror=format-security ‘ ‘LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 ‘ ‘CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2’

可以看得出來,在不同的Linux 分發版本中,Python 解釋器的版本以及優化方法存在一些差異。對比起來 Ubuntu 20.04 的Python解釋器無論是Pystone 還是Pytest-benchmark 都要表現的更好一些。

NumPy 與SciPy

對於一些場景,Python 應用需要使用NumPy 以及SciPy。通常我們通過pip3 install numpy scipy 安裝其二進制版本。一些場景下,使用BLIS對SciPy和NumPy工作負載進行基準測試可以確定額外的性能改進。

注:BLIS是一個可移植的軟件框架,用於實例化高性能BLAS高性能稠密線性代數庫。

  • 在Ubuntu上用BLIS安裝NumPy和SciPy

    在Ubuntu上安裝python3-numpy 與python3-scipy程序包將安裝帶有BLAS和LAPACK庫的NumPy和SciPy。用BLIS和OpenBLAS在Ubuntu和Debian上安裝SciPy和NumPy:

    sudo apt -y install python3-scipy python3-numpy libopenblas-dev libblis-dev
    sudo update-alternatives --set libblas.so.3-aarch64-linux-gnu \
    /usr/lib/aarch64-linux-gnu/blis-openmp/libblas.so.3
    

    在blas 與lapack 之間進行切換

    sudo update-alternatives --config libblas.so.3-aarch64-linux-gnusudo update-alternatives -config liblapack.so.3-aarch64-linux-gnu
    

PyPy

此外,2019年7月25日,PyPy 宣佈了對於Aarch64 架構的支持。在基於Graviton處理器的A1 實例上進行的性能測試。從結果來看,PyPy 對於Python 程序性能的提升是非常顯著的。

在一臺基於Graviton 2 的m6g.2xlarge的實例上運行Pystone,PyPy 的性能是CPython (Python 3.8.2)的21倍!! 性能的提升是非常的驚人了。

Go程序在Graviton 上的優化

Go是一種靜態類型的編譯型程序語言。Go支持開箱即用的arm64,可以在所有常見的發行版中使用。Go最新的升級提高了性能,所以請確保使用最新版本的Go編譯器和工具鏈。目前 Go的最新版本是1.14,而Amazon Linux 2 與Ubuntu 20.04 提供的安裝包的版本均爲1.13。在Ubuntu 環境下,安裝Go 最新版本的一個簡單的途徑還可以考慮通過snap 進行安裝。在snap 中提供的Go 的版本爲1.14.6。

Go 1.16

Go 的下一個版本1.16預計將於2021年初發布。預計Go編譯器將會通過以下列出的幾項特性來提高ARM 架構下程序的性能。

  • ARMv8.1-A Atmoics指令,可顯着提高Graviton 2上的互斥公平性和速度,以及帶有v8.1和更新指令集的現代Arm內核。
  • 複製性能得到改善,尤其是當地址未對齊時。

關於系統優化的話題總是會有太多的內容值得探討。隨着新的基於ARM 的實例的普及,越來越多的開發者一定會遇到應用優化的問題。這篇博客權當是拋磚引玉之作,期待你們的經驗與反饋。我的郵箱地址是 [email protected]

作者介紹

費良宏

費良宏,AWS Principal Developer Advocate。在過去的20多年一直從事軟件架構、程序開發以及技術推廣等領域的工作。他經常在各類技術會議上發表演講進行分享,他還是多個技術社區的熱心參與者。他擅長Web領域應用、移動應用以及機器學習等的開發,也從事過多個大型軟件項目的設計、開發與項目管理。目前他專注與雲計算以及互聯網等技術領域,致力於幫助中國的 開發者構建基於雲計算的新一代的互聯網應用。

原文鏈接

https://amazonaws-china.com/cn/blogs/china/optimization-of-arm-example-application/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章