ubuntu c++ 实现自动回车键功能_从X86到ARM,实现C和C++语言90% Code自动迁移
x86 與 ARM 之爭,已經(jīng)貫穿了很長時間,過去一直是 x86 架構(gòu)比較受到市場和開發(fā)者的歡迎。但是自從移動互聯(lián)網(wǎng)、物聯(lián)網(wǎng)和邊緣計算興起之后,ARM 似乎已經(jīng)找到最適合自己生存的土壤。
架構(gòu)之爭的平臺技術(shù)拐點,已然來臨。
現(xiàn)在,每個人手上都有一臺智能計算終端,移動應(yīng)用逐漸云化,5G 催生了云游戲的誕生;Web 應(yīng)用的加密性越來越重要,HTTPS 流量越來越大;大數(shù)據(jù)分布式并行計算成為主流等,這些都讓 x86 架構(gòu)的不足逐漸顯露出來。
所以才會有現(xiàn)在所遇到的情況,即不得不從 x86 上的應(yīng)用遷移至 ARM 上。但也正因為這是兩個完全不同的平臺,所以在遷移過程中會遇到各種各樣的問題。
以下內(nèi)容經(jīng)由 InfoQ 編輯整理自DevRun開發(fā)者沙龍中張永正和楊少洪老師的分享。
1?鯤鵬軟件遷移概述和方法論
?首先要搞懂:為什么要遷移?
上圖所示為程序執(zhí)行的過程和對應(yīng)的計算棧。任何一臺計算機都是由硬件和軟件組成的,類似于最底層的基礎(chǔ)物理原材料、晶體管、寄存器、微架構(gòu)等都屬于硬件層面。而軟件層面則特指由高級語言、匯編語言開發(fā)的應(yīng)用程序。要執(zhí)行這些應(yīng)用程序,需要底層 CPU 支持由匯編器形成二進(jìn)制的機器碼(由指令和數(shù)據(jù)組成)去運行。
因此就需要底層計算平臺能夠支持該 CPU 的指令才可以,這也是在 x86 和鯤鵬編譯的區(qū)別之處。
在 x86 和鯤鵬上編譯之后的指令差異是哪些?可以參照下圖左側(cè),顯而易見這是一套非常簡單的代碼,分別在 x86 和鯤鵬上編譯之后形成三點指令差異:
首先是匯編不同,x86 上是兩條 mov 指令,通過把 A 和 B 的變量從內(nèi)存當(dāng)中取到寄存器,并將兩值相加,再由一條 mov 指令寫回內(nèi)存;鯤鵬上則是通過兩條 ldr 指令、一條 add 指令以及一條 str 指令完成整個過程。
其次是指令長度不同,x86 上 mov 指令是 24 位的,ldr 指令是 16 位的,在鯤鵬上則都是 32 位;第三則是寄存器不同,x86 和鯤鵬處理器使用的向量寄存器不同,其向量指令級也存在差異。
鯤鵬處理器與 x86 處理器的指令差異
這也正是做遷移的原因,因為在 x86 上所編譯出來的應(yīng)用程序因為有以上三點的不同,因此無法在鯤鵬上直接運行。
?從 x86 到鯤鵬,遷移五步走戰(zhàn)略
從大量的實踐中得以總結(jié)出一些規(guī)律和方法,主要分為以下 5 個步驟:
1、遷移準(zhǔn)備,主要以收集硬件信息和軟件棧信息為主;
在這期間,主要收集硬件和軟件信息。硬件方面的信息主要是收集芯片和服務(wù)器的型號,從而方便提供配置性能差不多的鯤鵬服務(wù)器;其次是收集軟件棧信息,主要分為操作系統(tǒng)、虛擬機、中間件、編譯器、上層依賴的開源軟件、商業(yè)軟件、業(yè)務(wù)軟件等信息。
2、遷移分析,對收集到的信息和軟件棧做初步分析,判斷是否真正需要遷移,評估遷移的工作量;
下圖左側(cè)就是一個非常完善的技術(shù)棧,底層有芯片,中間層為 OS、虛擬機、編譯器等相對應(yīng)的運行環(huán)境。上層是業(yè)務(wù)軟件,分為開源、自研和商用軟件。
開源軟件的遷移相對較為簡單,其中一部分開源軟件在 ARM 上已經(jīng)被編譯好的包,直接下載即可。即便沒有現(xiàn)成的編譯成果,自行下載原碼進(jìn)行編譯也并不復(fù)雜方便;自研軟件的遷移需要注意語言類型的差異,編譯型語言是需要重新編譯之后才能運行在新環(huán)境上,但是對于解釋型的語言來說就沒有重新編譯的需要,只要更換所依賴的虛擬機就可以;商用軟件則較為麻煩一些,首先可以通過聯(lián)系廠商獲取它對應(yīng) ARM 架構(gòu)下的軟件版本,如果沒有的話就需要尋找有類似功能的軟件做替換。
此外像運行環(huán)境、虛擬機、編譯器和操作系統(tǒng)這些也是要進(jìn)行替換,但是這些并非需要重新編譯,因為在華為云鯤鵬論壇內(nèi)有軟件倉庫,可以直接去軟件倉庫下載由鯤鵬官方所做的經(jīng)過驗證的版本。
3、編譯遷移,分析完成之后就可以著手遷移工作,主要分為代碼遷移和軟件包遷移;
遷移分析之后可以進(jìn)行代碼的編譯和打包,編譯主要涉及兩個到代碼遷移和軟件包遷移。
其中代碼遷移需要區(qū)分語言,像 C/C++ 和指令級的差異是比較大的,因此在 x86 上編譯出來的應(yīng)用程序無法在在鯤鵬上直接使用,因此要在鯤鵬上重新編譯才可以。此外編譯型語言所涉及的修改點相對更多,因為代碼當(dāng)中有可能蘊含一些對指令級相關(guān)的宏定義或者功能性函數(shù);但是對于 Java/Python 這種解釋型語言來說就會簡單很多。如果是純 Java/Python 的程序,就無須做編譯,因為本身的虛擬機已經(jīng)對指令級進(jìn)行了屏蔽,只要更換虛擬機就可以。
對于軟件包遷移來說,首先需要掃描該軟件包是否存在依賴庫或者依賴的可執(zhí)行程序,這些庫和可執(zhí)行程序如果是用 C 語言寫的是需要重新編譯的,編譯之后重新把軟件包打包即可。
4、性能調(diào)優(yōu),驗證完成之后對性能指標(biāo)進(jìn)行測試,進(jìn)行性能調(diào)優(yōu);
由于大部分軟件對性能都有要求,因此在遷移完成之后需要對性能進(jìn)行調(diào)優(yōu),這里總結(jié)了【建立基準(zhǔn) - 壓力測試 - 確定瓶頸 - 實施優(yōu)化 - 確認(rèn)效果】這五步法。
首先需要建立調(diào)優(yōu)基準(zhǔn),該基準(zhǔn)根據(jù)當(dāng)前的硬件配置、組網(wǎng)、測試模型來做綜合評估,以建立合理的條有目標(biāo);其次在調(diào)優(yōu)目標(biāo)建立后,通過壓測工具對軟件或系統(tǒng)進(jìn)行加壓,在加壓過程中暴露性能瓶頸,確定瓶頸之后對瓶頸進(jìn)行優(yōu)化;第四,注意在優(yōu)化過程中要及時記錄,因為優(yōu)化并不一定是正向的,出現(xiàn)負(fù)向優(yōu)化時需要及時回退;最后在優(yōu)化措施實施完成后,需要重新啟動壓力測試工具以確認(rèn)優(yōu)化效果。
這個過程并非一蹴而就,有可能其中某個步驟需要經(jīng)過多次循環(huán)之后才能達(dá)到既定目標(biāo)。
5、測試與認(rèn)證,保障商用上線。
和日常軟件開發(fā)一樣,需要對其進(jìn)行功能、性能、長穩(wěn)等層層測試,以確保能達(dá)到商用標(biāo)準(zhǔn)。此外也可以拿軟件和系統(tǒng)到鯤鵬上做鯤鵬展翅認(rèn)證,其可以擴展應(yīng)用的軟件使用空間并能夠加入鯤鵬生態(tài)。
2?C/C++ 代碼編譯原理及構(gòu)建流程
?編譯型語言,從源碼到可執(zhí)行程序的歷程
C、C++、GO 都是非常典型的編譯型語言,編譯型語言所開發(fā)的程序從 x86 平臺移植到鯤鵬平臺時一般都需要重新編譯才能運行,這點上文也已經(jīng)提到了。那么為什么需要重新編譯才能運行呢?接下來舉個簡單的例子。
上圖為 test.c 的源碼文件,首先經(jīng)過預(yù)處理,把代碼里面以 # 號開頭的代碼片斷編譯為預(yù)處理文件,預(yù)處理文件再經(jīng)由編譯生成匯編代碼。匯編代碼經(jīng)過匯編器生成目標(biāo)文件,這也就是常說的機器碼。然而機器碼是無法直接運行的,所以需要聯(lián)接動態(tài)庫或者靜態(tài)庫來最終生成可執(zhí)行文件。
?編譯構(gòu)建的過程
從代碼工程的角度看,其可以分為兩類:一類是編譯構(gòu)建的腳本,二是源碼。在編譯構(gòu)建的腳本中一般會存在 Makefile、cmakelist 等一系列腳本文件,C 和 C++ 的源碼一般是有 src、tests 等文件。
那么編譯構(gòu)建腳本類文件在遷移過程中會涉及哪些因素?一般會涉及到編譯選項的移植,源碼類文件會涉及到編譯宏,另外可能還會有編譯器自帶的 Builtin 函數(shù)的移植、SSE intrinsic 函數(shù)移植等。需要強調(diào)的是這里提到的是遷移過程中可能會涉及到的移植項,但在實際遷移過程中可能只需要編譯選項或修改編譯宏就可以。
C/C++ 代碼編譯構(gòu)建過程
首先要從獲取源碼開始,可以通過 GitHub 等開源社區(qū)來獲取;其次需要選擇所需的編譯環(huán)境,就是安裝編譯器 gcc 等;之后根據(jù)源碼的編譯腳本生成 Makefile 文件,再用 Makefile 編譯生成可持續(xù)文件。如果這部分代碼之中有依賴 x86 平臺的 SO 庫,那么這部分的依賴庫是需要重新編譯替換的。在編譯完成之后進(jìn)行安裝部署,之后進(jìn)入到實際的系統(tǒng)之中進(jìn)行測試。
?典型的移植類問題
在對編譯構(gòu)建的流程有基本理解后,就需要深入了解實際遷移過程中所涉及到的各種移植項。
編譯腳本和編譯選項的移植
以上圖為例,其中 x86 下 -m64 代碼的主要功能是將應(yīng)用程序編譯為 64 位,對應(yīng)到鯤鵬上是用 -mabi=lp64 的編譯選項。上文有提到這編譯選項需要在腳本中修改,對應(yīng)的 Cmakelists 里有可能存在 add_defin 等多種定義方式。
再看常用的數(shù)據(jù)類型移植,眾所周知 x86 平臺上默認(rèn)的 char 類型是一種有符號的類型,對應(yīng)到鯤鵬上則是無符號類型。因此在移植過程中需要顯示定義并將 char 類型定義為有符號。一種方法是在源代碼里加上 signed char,但是缺點是可能改不全從而引發(fā)一些不可預(yù)知的問題。另一種方法是直接用 fsigned-char 來修改,在不同架構(gòu)下差異化的編譯選項也可以通過 gcc 文檔進(jìn)行查詢。
編譯宏的移植
如果有相同的代碼片斷在不同平臺下可能會存在不同分支,需要將不同架構(gòu)下的性能優(yōu)勢發(fā)揮到較高水平。但是對于編譯器來說,如何才能得知要編譯哪些分支代碼呢?這就是編譯宏的作用。
如果大家對大型開源軟件有接觸過,相信對上圖這些編譯選項都不會陌生。gcc 編譯器所自帶的 x86 編譯選項就是 x86_64,對應(yīng)到鯤鵬平臺上是 ark-64。當(dāng)然除了 gcc 編譯器自帶的自定義宏,在實際場景中也需要對自研代碼進(jìn)行自定義,在鯤鵬上也是需要進(jìn)行自定義替換。
不過針對編譯宏的替換只是其中一個方面,其最重要的是對編譯宏下面的代碼實現(xiàn)移植。x86 代碼上有些編譯器自帶自定義宏,比如 smd 屬性相關(guān)的宏在 x86 上是 SSE 開頭的宏,對應(yīng)到鯤鵬平臺上就需要自定義它的編譯宏和所相對應(yīng)的分支。
3.Builtin 函數(shù)移植
Builtin 函數(shù)是編譯器自帶的函數(shù),其在實際遷移項目中相當(dāng)常見,主要是 crc32 校驗值的計算。需要移植的普通 builtin 函數(shù)實際并不多,大部分需移植的 builtin 函數(shù)集中在 SSE intrinsic 函數(shù)內(nèi)。
通過上圖可以看到在 x86 平臺上其和在鯤鵬平臺上是類似的,從命名來看有差異的地方就只存在于架構(gòu)。
內(nèi)聯(lián)匯編函數(shù)的移植
內(nèi)聯(lián)匯編對于部分開發(fā)者來說平時接觸的會比較少,所以又可能會感覺到陌生。
上圖列舉了將字節(jié)序進(jìn)行反序的例子,比如 0X56781314 反序輸出的是 0X14137856,x86 上對應(yīng)的是 bswap 指令,鯤鵬對應(yīng)的是 rev 指令,其它有些操作和寄存器都是基于內(nèi)聯(lián)匯編的語法規(guī)則進(jìn)行替換的。上圖的另一個例子是 Builtin 函數(shù),列舉了內(nèi)聯(lián)匯編轉(zhuǎn)換用鯤鵬上面的 Builtin 函數(shù)做替換的例子。比如 popcount 是對二進(jìn)制數(shù)里面的 1 進(jìn)行計數(shù),對應(yīng)到鯤鵬平臺上所替換的是 popcountll。
5.SSE intrinsic 函數(shù)移植(SIMD 技術(shù))
關(guān)于 SSE intrinsic 函數(shù)的移植,在這之前需要先了解 SIMD 的技術(shù)。SIMD(Single Instruction Multi Data) 是一種單指令處理多數(shù)據(jù)流的并行處理技術(shù),能夠在批量數(shù)據(jù)操作時進(jìn)行向量 化運算加速,具有較高的執(zhí)行效率,在多媒體處理、矩陣運算等場景都有廣泛的應(yīng)用。
Intel 的 SIMD 擴展指令統(tǒng)稱 SSE,主要分為三類,MMX 是 64 位寄存器,SSE 到 SSE4 是 28 位的,三是 AVX256 和 AVX512。鯤鵬基于 SIMD 的技術(shù)發(fā)展比較成熟,現(xiàn)在有些基于開源量的 NEON 庫主要是在圖象處理和視頻處理層面。
6.SSE intrinsic 函數(shù)移植(MMX/SSE)
經(jīng)過調(diào)用編譯器就能夠基于 C 函數(shù)調(diào)用完成對 SIMD 技術(shù)的應(yīng)用,極大方便了開發(fā)者。
以上圖為例,在 x86 上用的是 -m64 的向量,add 是關(guān)鍵字,而且這是加法運算,后面 32 是數(shù)據(jù)類型。對應(yīng)到鯤鵬上是 int32×2 然后再做加法運算,這常用的 C 函數(shù)規(guī)則是類似的。針對 SSE 指令,從內(nèi)存中加載 4 個單精度浮點數(shù)據(jù)到寄存器,x86 是 load,對應(yīng)到鯤鵬用的是 vld1q。
7.SSE intrinsic 函數(shù)移植(AVX)
AVX 指令和 MMX 類似,只不過其位數(shù)不同。以 AVX 指令使用了 256 位寄存器運算為例,向量 A 和向量 B 中分別存儲了 8 個單 精度浮點型 (32 位)。該指令將向量 A 和向量 B 中的 8 個數(shù)值分別相加,并將結(jié)果以返回值的形式返回 (結(jié)果中依然是 8 個單精度浮點型數(shù)據(jù)) ,最后再從向量寄存器中分別取出 8 個單精度浮點數(shù)累加得到結(jié)果。
對應(yīng)到鯤鵬方面,鯤鵬處理器采用精簡指令集,使用 128 位寄存器實現(xiàn) SIMD(Single Instruction Multi Data) 計算。在實現(xiàn)本例 16 個浮點數(shù)的相加時,通過兩條 vaddq_f32 指令來分別完成,每條指令完成兩組共 8 個浮點數(shù)算,最后再從向量寄存器中分別取出 8 個浮點數(shù)累加。
3?寫在最后
對于開發(fā)者而言,代碼和軟件遷移是一套必須要掌握的技能。尤其是各種智能終端數(shù)量暴漲,物聯(lián)網(wǎng)飛速發(fā)展的當(dāng)下,x86 平臺已經(jīng)難以適應(yīng)全生態(tài)的發(fā)展,從 x86 遷移至 ARM 平臺,正是現(xiàn)在的大勢所趨。而鯤鵬生態(tài),則為每一位有遷移需求的開發(fā)者提供了最便利的工具和環(huán)境。沒有哪一款平臺是最好的,只有最適合業(yè)務(wù)的那款平臺,從 x86 到 ARM,答案正在逐漸清晰。
溫馨提示:
請搜索“AI_Architect”或“掃碼”關(guān)注公眾號跟蹤技術(shù)動態(tài),點擊“閱讀原文”獲取更多技術(shù)和精彩內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的ubuntu c++ 实现自动回车键功能_从X86到ARM,实现C和C++语言90% Code自动迁移的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python bootstrap-fil
- 下一篇: python按位右移的作用_python