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