爲什麼必須將代碼從x86遷移到ARM,這篇文章給你答案

“我們非常希望 ARM 和鯤鵬的生態能成爲下一個計算產業迭代的方向。”在 6 月 8 日於成都舉辦的華爲 DevRun 開發者沙龍——四川鯤鵬開發者嘉年華上,華爲鯤鵬計算產業開源與生態營銷總監梁冰對計算產業未來展望道。

新基建風口下,算力一躍成爲了新的生產力,雲、AI 與 5G 則是新的生產工具,技術聚變將引發商業裂變,帶動各行各業的數字化快速發展。基於 5G 等新興技術的創新應用催生多樣化算力的需求,市場既需要通用計算算力也需要異構計算算力。此外,摩爾定律的逐漸放緩,讓算力和性能陷入一系列發展瓶頸,市場對創新架構的需求日益加深,計算平臺的創新之戰一觸即發。

在此背景下,x86 架構的不足越發明顯,功耗大、通用寄存器數量少、計算機硬件利用率低、尋址範圍小等問題凸顯,難以跟上算力發展的速度。與此同時,ARM 架構在移動互聯網盛行的當下卻開始煥發出別樣的生命力。

“基於 ARM 架構來設計的鯤鵬,其成功的前提是早早地便看到了未來計算機算力架構的迭代之路。對華爲來說,不光要在中國攜手合作夥伴共建鯤鵬生態,爲更多企業帶來價值,更爲重要的是要融入全球 ARM 的生態,共同推進 ARM 進階爲下一代計算機平臺的實施標準。”梁冰對鯤鵬生態的意義闡述道。

從 x86 遷移到 ARM 架構的過程並不簡單,本次活動中,華爲鯤鵬計算專家對於鯤鵬軟件遷移路徑也進行了非常全面細緻的講解,同時針對軟件遷移過程中可能遇到的問題及解決方案也進行了相關講解,還爲現場開發者設置了實操演練環節,一對一指導下進行鯤鵬軟件遷移線上實驗。

從 x86 向鯤鵬遷移的必要性

衆所周知,計算機是由軟件和硬件組成的,上層的軟件是通過指令集驅動下層的硬件,軟件想要跑在 CPU 上的話,那它必須要有對應的指令集。

如上圖所示,整個計算機的計算基礎架構,從底層的晶體管、物理原材料,二極管也就是邏輯門電路,到往上走的微架構、自評級架構,再往上面走就到了操作系統所完成的二進制機器譯碼彙編高級語言、JavaC 等等,整個技術站從複雜到抽象,技術語言也從經歷一個簡單的交換指令發展爲彙編進行訪存和鎖存,再到形成機器碼,這個過程中最核心的變化在指令集上。

想要成功運行,底層計算平臺就必須能夠支持該 CPU 的指令纔可以,這也是在 x86 和鯤鵬編譯的不同之處。

如上圖所示,x86 和鯤鵬使用的指令是不一樣的,簡單來講,在鯤鵬上使用的是精簡指令集,而在 x86 上使用的是一個複雜的指令集。綜合來講,它有三點主要的差異:

  • 架構差異:x86 和鯤鵬處理器 (aarch64) 屬於不同的架構。

  • 指令集差異:x86-- 複雜指令集,鯤鵬處理器 – 精簡指令集。

  • 向量寄存器差異:x86 和鯤鵬處理器使用向量寄存器不同,向量指令集也存在差異。

從這三點出發,一個在 x86 上運行的程序根本不可能毫無阻礙地就可以在鯤鵬上使用,必須經過編譯,同時也證明了遷移的必要性。

遷移的五個步驟

1. 遷移準備:信息收集 & 環境申請

信息的收集主要分爲兩部分,首先是硬件信息的收集,主要就是一些型號,目的是根據此類信息匹配一個 x86 的服務器;其次是收集軟件棧信息,包括操作系統、虛擬機、中間件、編譯器、上層依賴的開源軟件、商業軟件、業務軟件等信息。

2. 遷移分析:軟件棧分析 & 編程語言分析

這一過程要做的就是對收集到的信息和軟件棧做初步分析,目的是判斷是否真正需要遷移,評估遷移的工作量。

對開源軟件來說,因爲社區發展已經比較成熟,遷移相對較爲簡單,通過基於鯤鵬的架構分支或者鯤鵬支持的軟件包,自行安裝即可。對於自研軟件來講,情況則較爲複雜,如 C、C++ 這類編譯型軟件,從指令集差異化出發,需要重新編譯後才能完成遷移,而 Java、Python 這種解釋型的語言,因爲其虛擬機如 JDK、PVM 已經把上層的一些跟指令集相關的東西屏蔽掉了,平滑地遷移過去即可。對於商用軟件而言,不會公開源碼,如果需要遷移,就必須要聯繫廠家去編譯一個鯤鵬的版本,並且完成一系列的適配。

此外像運行環境、虛擬機、編譯器和操作系統這些也是要進行替換,但是這些並非需要重新編譯,因爲在華爲雲鯤鵬論壇內有軟件倉庫,可以直接去軟件倉庫下載由鯤鵬官方所做的經過驗證的版本。

3. 編譯遷移:代碼遷移 & 軟件包遷移

編譯型的語言,之所以遷移起來比較困難,原因就在於涉及到比較多的遷移點,下面將從代碼和軟件包兩方面進行闡述。

對於對指令集有依賴的代碼來說,與 x86 架構相關的,都需要替換成 ARM 架構下的語言;像以 Java、Python 爲代表的解釋型語言,換一下 JDK 和 PVM 就行了,如果語言中調用了編譯型語言,必須把這部分重新編譯纔可行。對於軟件包來說,其遷移與 Java、Python 語言類似,即掃描出來裏邊的對編譯型語言的依賴,把這一部分依賴進行替換即可。

4. 性能調優:性能指標測試 & 性能優化

經過前面幾個步驟之後,軟件遷移其實就基本完成了,之後要對性能進行調優,主要分爲建立基準 、壓力測試 、確定瓶頸、 實施優化、 確認效果五個步驟。

首先需要建立調優基準,該基準根據當前的硬件配置、組網、測試模型來做綜合評估,以建立合理的條有目標;其次在調優目標建立後,通過壓測工具對軟件或系統進行加壓,在加壓過程中暴露性能瓶頸,確定瓶頸之後對瓶頸進行優化;第四,注意在優化過程中要及時記錄,因爲優化並不一定是正向的,出現負向優化時需要及時回退;最後在優化措施實施完成後,需要重新啓動壓力測試工具以確認優化效果。

5. 測試與認證:壓力測試 & 長穩測試 & 規模商用

調優結束之後,接下來就要把功能運力、長穩運力以及性能運力都跑一遍,達到一個商用的標準,就可以籌備上線了。此外也可以將軟件和系統進行鯤鵬展翅認證,其可以擴展應用的軟件使用空間並能夠加入鯤鵬生態。

不同語言的遷移注意事項

實際上,像 Java、Python、Perl 這種跨平臺的開發語言,它的遷移的技術難度相對來說是比較低的,主要是因爲 Java 有一個 JBM,Python 中存在一個解釋器,它們屏蔽了大部分的平臺架構上的差異。與之相反,C 和 C++ 的難度相對來說要高一些,原因是如內斂函數還有 x86 加速的一些指令,無法支持像微軟這種閉源的開發架構。

典型的如 C/C++/Go 語言,都屬於編譯型語言。編譯型語言開發的程序在從 x86 處理器遷移到鯤鵬處理器時,必須經過重新編譯才能運行。如下圖所示,源碼需要由編譯器、彙編器翻譯成機器指令,再通過鏈接器鏈接庫函數才能生成機器語言程序。

接下來就是 C/C++ 代碼的編譯構建了,這個過程一共分爲六步:

  • 獲取源碼:通過 github 或第三方開源社區獲取

  • 準備編譯環境:安裝編譯器 gcc 等

  • 使用源碼中的 CMakeLists.txt 或 configure 腳本生成 makefile

  • 執行 makefile 編譯可執行程序

  • 替換依賴庫:重編譯或替換依賴 x86 平臺的 so 庫

  • 將可執行程序安裝部署到生產或測試系統

既然是最爲複雜的,C/C++ 語言的遷移問題也是涉獵最廣泛的,主要涉及到七類問題:

  • 編譯腳本和編譯選項的移植:以 x86 下 -m64 代碼爲例,其主要功能是將應用程序編譯爲 64 位,對應到鯤鵬上是用 -mabi=lp64 的編譯選項,此類編譯選項需要在腳本中修改;此外, x86 平臺上默認的 char 類型是一種有符號的類型,對應到鯤鵬上則是無符號類型,在移植過程中需要顯示定義並將 char 類型定義爲有符號,方法一是在源代碼里加上 signed char,方法二是直接用 fsigned-char 來修改。

  • 編譯宏的移植:編譯宏的作用就是讓編譯器知道編譯哪些分支代碼能夠在不同架構下達到最優性能。如何對編譯宏下面的代碼實現移植?86 代碼上有些編譯器自帶自定義宏,比如 smd 屬性相關的宏在 x86 上是 SSE 開頭的宏,對應到鯤鵬平臺上就需要自定義它的編譯宏和所相對應的分支。

  • Builtin 函數移植:Builtin 函數是編譯器自帶的函數,其在實際遷移項目中相當常見,主要是 crc32 校驗值的計算。需要移植的普通 builtin 函數實際並不多,大部分需移植的 builtin 函數集中在 SSE intrinsic 函數內。

  • 內聯彙編函數的移植:第一種是指令替換,x86 上對應的是 bswap 指令,鯤鵬對應的是 rev 指令,其它有些操作和寄存器都是基於內聯彙編的語法規則進行替換的。第二種是 Builtin 函數的替換,以 x86 的指令 popcnt 爲例,比如 popcount 是對二進制數裏面的 1 進行計數,對應到鯤鵬平臺上所替換的是 popcountll。

  • SSE intrinsic 函數移植(SIMD 技術):Intel 的 SIMD 擴展指令統稱 SSE,主要分爲三類,MMX 是 64 位寄存器,SSE 到 SSE4 是 28 位的,三是 AVX256 和 AVX512。鯤鵬基於 SIMD 的技術發展比較成熟,現在有些基於開源量的 NEON 庫主要是在圖象處理和視頻處理層面。

  • SSE intrinsic 函數移植(MMX/SSE):針對 MMX 指令,x86 上用的是 -m64 的向量做加法運算,對應到鯤鵬上是 int32×2 然後再做加法運算,類似於常用的 C 函數規則;針對 SSE 指令,從內存中加載 4 個單精度浮點數據到寄存器,x86 是 load,對應到鯤鵬用的是 vld1q。

  • SSE intrinsic 函數移植(AVX):以 AVX 指令使用了 256 位寄存器運算爲例,向量 A 和向量 B 中分別存儲了 8 個單 精度浮點型 (32 位),對應到鯤鵬處理器上,使用 128 位寄存器實現 SIMD(Single Instruction Multi Data) 進行計算。
    儘管解釋性語言難度降低,但 Java、Python 代碼遷移過程中同樣有一些問題需要注意。

如上圖所示,Java 想要進行遷移的話,首先需要安裝運行環境 JDK,Java 源碼通過 Java 編譯器之後就會生成一個 Java 的字節碼,這時候可能 jar 包會有一些 SO 庫的依賴,那就需要鏈接進行打包。

這整個的過程,存在遷移修改點的地方有二,一是 JDK 的安裝,遷移過來推薦使用華爲的 JDK 或者 OpenJDK;二是對 SO 庫這個二進制庫的依賴,如果你是在 x86 下編譯的,毫無疑問,這在鯤鵬下面是沒辦法進行運行的,所以你需要拿到相應的源碼或者找到 aarch64 的 SO 庫來進行替換,最後進行重新打包。

再來看 Python 源碼的遷移,其實與 Java 很類似,也是需要從編譯環境和 SO 庫兩大方面入手修改。環境上推薦使用 A32,Python3 你也可以通過樣本安裝,也可以通過源碼安裝;SO 庫有多種類型,但對於各種方式的 SO 庫,最後都是對應爲一個 SO,定義爲 SO 庫,需要的步驟也都是一致的,即裝配環境、重新編譯、重新替換。

不同的地方只是前面安裝的是 Python 的運行環境。Python 源碼同樣通過解釋器生成一個字節碼,這時候可能我們會依賴外部的一些 Python import 模塊進來,這些模塊裏面可能有一些 SO 庫,Python 解釋器的解釋執行後就是部署運行了。

相對於 C++ 來說,Java/Python 的遷移點並不是太多,總結下來,主要需要注意兩點:

  • 編譯器包括解釋器的安裝、遷移,這裏有兩種方式,方式一是通過 YAM 源的方式進行安裝,方式二是找到源碼進行編譯重新安裝。

  • x86 依賴 SO 庫的情況下,需要找到 SO 庫相應的源碼,進行重新編譯後實現替換。

寫在最後

“拿華爲的話說,就是自己的降落傘自己先跳。長虹大數據平臺的規模比較大,有一百多個服務器,原來是一個 PB 級的數據存儲,涉及到的整個生態組件有 20 多個,我們將原來存在的 1700 多萬的終端業務遷移到基於鯤鵬的大數據計算平臺,耗時近 5 個月。鯤鵬的架構在 HBS 場景下優勢凸出,另外在存儲、IO 等方面基本上是持平,總體來說,鯤鵬的芯片表現性能都還不錯。”長虹計算產業事業部技術總監蒲文龍這樣評價到同行者華爲鯤鵬。

無獨有偶,麒麟軟件有限公司技術總監李洋同樣讚揚道,“華爲鯤鵬的代碼遷移工具,包括分析掃描工具、代碼遷移工具及性能優化工具,這是作爲開發者一定要去了解的非常方便的工具,它可以讓開發者快速地分析系統軟件源代碼,以及對所需要的依賴包進行編譯和重構。”

對於開發者來說,遷移是一套必須掌握的技能;對於互聯網企業來說,遷移是助力企業抓住未來趨勢的一個必要動作。從 x86 架構到 ARM 架構,計算產業的未來已經漸漸明晰,而鯤鵬作爲先行者,生態的力量也愈發強大,始終秉持着“硬件開放、軟件開源、使能夥伴”的初心,逐漸發展成爲滋養新計算產業的一方沃土。

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