步驟 1:準(zhǔn)備
您需要了解源平臺與目標(biāo)平臺之間的差別。例如,需要知道源平臺上的字節(jié)排列順序是否與目標(biāo)平臺上的字節(jié)排列順序有所不同。如果源平臺是 Solaris/x86,則您應(yīng)該考慮字節(jié)排列順序,因為 Linux on POWER 是大端字節(jié)的,而 Solaris/x86 是小端字節(jié)的。
還要確定目標(biāo)平臺上是否包含所有必需的第三方包(比如數(shù)據(jù)庫和類庫)。對于 32 位應(yīng)用程序,要考慮是否有必要遷移到 64 位。在下面的 一般遷移事項 小節(jié)中,將提供字節(jié)排列順序以及 32 位到 64 位問題的信息。
此外,要決定哪個編譯器用于目標(biāo)平臺。如果應(yīng)用程序是性能敏感的,那么還要考慮使用原始編譯器。在 Linux on POWER 的開發(fā)環(huán)境 小節(jié)中,將提供關(guān)于 Linux on POWER 的可用編譯器的詳細(xì)信息。
步驟 2:配置
這一步中包括設(shè)置開發(fā)環(huán)境、設(shè)置環(huán)境變量、對 makefile 進行更改,等等。在結(jié)束這個階段時,應(yīng)該可以開始構(gòu)建應(yīng)用程序了。
步驟 3:構(gòu)建
這一步中包括修復(fù)編譯器錯誤、連接程序錯誤和其他信息。代碼經(jīng)常要多次重復(fù)執(zhí)行步驟 2 和步驟 3 才能生成沒有問題的構(gòu)建。
步驟 4:運行時測試和調(diào)試
成功構(gòu)建應(yīng)用程序后,還要對其進行測試,檢查運行時錯誤。
步驟 5:性能調(diào)優(yōu)
現(xiàn)在,移植的代碼已經(jīng)可以在目標(biāo)平臺上運行。可以通過監(jiān)控性能來確保移植的代碼按照預(yù)期的那樣執(zhí)行。如果沒有按照預(yù)期的那樣執(zhí)行,必須進行性能調(diào)優(yōu)。在本文的 性能調(diào)優(yōu) 小節(jié)中,將提供關(guān)于可用于 Linux on POWER 的性能調(diào)優(yōu)工具的詳細(xì)信息。
步驟 6:打包
您是否要將得到的代碼傳送給其他人?如果要傳送,您想使用哪種打包方法?Linux 提供了多種方法來打包應(yīng)用程序,比如自安裝外殼腳本或 RPM。軟件打包 小節(jié)中將提供關(guān)于 Linux 的軟件打包的詳細(xì)信息。
![]() ![]() |
![]()
|
一般遷移事項
這一節(jié)將提供何時將應(yīng)用程序從 32 位遷移到 64 位的信息,以及跨越字節(jié)排列順序障礙的應(yīng)用程序要考慮的一些問題。從 Solaris on x86 平臺上遷移的應(yīng)用程序?qū)⒖缭阶止?jié)排列順序障礙。熟悉 32 位到 64 位遷移和字節(jié)順序的開發(fā)人員可以跳到下一小節(jié) “Linux on POWER 的開發(fā)環(huán)境”。
32 位到 64 位
一旦決定移植到 Linux on POWER,如果應(yīng)用程序目前是 32 位的,那么還要考慮將應(yīng)用程序移植到 64 位。不過,不需要 64 位功能的 32 位應(yīng)用程序應(yīng)該保持 32 位。涉及遷移到 64 位的任何移植工作都應(yīng)該分為兩步:
首先,以 32 位形式遷移到目標(biāo)平臺。
然后才能遷移到 64 位。
否則,因為平臺遷移導(dǎo)致的問題很容易與因為遷移到 64 位導(dǎo)致的問題混淆。也就是說,如果應(yīng)用程序可以滿足下列條件,則應(yīng)該移植到 64 位:
受益于大于 4GB 的虛擬地址空間。
受益于更多的物理內(nèi)存(大于 4GB),同時用戶可能在擁有大于 4GB 的物理內(nèi)存的系統(tǒng)中進行部署。
受益于 64 位整數(shù)大小。
受益于完整 64 位寄存器,以便進行有效的 64 位運算。
使用大于 2GB 的文件。
應(yīng)用程序可以保持 32 位,同時仍舊在 64 位 Linux on POWER 內(nèi)核中運行,而無需進行任何代碼更改。基于 POWER 處理器的 IBM Linux 服務(wù)器支持 32 位和 64 位應(yīng)用程序同時在 64 位架構(gòu)中運行,而在這兩種模式之間不會有任何性能下降。
將 32 位應(yīng)用程序轉(zhuǎn)換為 64 位應(yīng)用程序時,可能會出現(xiàn)兩個基本問題:數(shù)據(jù)類型不一致 和使用不同數(shù)據(jù)模型的應(yīng)用程序之間的互操作。
64 位環(huán)境使用與 32 位環(huán)境不同的數(shù)據(jù)類型模型。對于 Linux on POWER,ILP 32 模型用于 32 位環(huán)境中,而 LP64 用于 64 位環(huán)境中。這兩種模型之間的區(qū)別在于長整型 和指針 的大小。因此,當(dāng)應(yīng)用程序從 ILP32 轉(zhuǎn)換為 LP64 時,數(shù)據(jù)類型中會發(fā)生基本變化。長整型和整型的大小不再相同。指針和整型的大小也不再相同。如果對象(如 struct 和 union)包含指針或長整型數(shù)據(jù)類型,那么它們的大小在 64 位環(huán)境中會比較大。通常,由這些差別引起的其他問題有:
數(shù)據(jù)截斷
指針賦值
數(shù)據(jù)對齊
數(shù)據(jù)共享
IBM XL 編譯器提供 -qwarn64 選項幫助檢查 32 位和 64 位模式之間可能出現(xiàn)的數(shù)據(jù)轉(zhuǎn)換問題。
將應(yīng)用程序從 32 位遷移到 64 位環(huán)境的主題在其他文章中已經(jīng)進行了大量講述。因此本文中我們將不再詳細(xì)說明如何處理這些移植問題。(請參閱 “將 Linux 應(yīng)用程序移植到 64 位系統(tǒng)” 了解更多信息)。
字節(jié)順序(字節(jié)排列順序)
因為 SPARC 和 POWER 架構(gòu)都是大字節(jié)端的,所以在這些平臺之間移植應(yīng)用程序時,不會存在字符排列順序問題。然而,如果將 Solaris on x86 應(yīng)用程序移植到 Linux on POWER,可能需要處理字節(jié)排列順序可移植性問題,因為 x86 是小字節(jié)端架構(gòu)。
在將應(yīng)用程序從一種架構(gòu)類型遷移至另一種架構(gòu)類型的過程中,經(jīng)常會遇到字節(jié)排列順序(endianness)問題。字節(jié)排列順序 是數(shù)據(jù)元素及其單個字節(jié)在內(nèi)存中存儲和表示時的順序。有兩類字節(jié)排列順序:大端字節(jié) 和小端字節(jié)。
對于大端字節(jié)處理器,比如 POWER、PowerPC™ 和 SPARC,在將字放在內(nèi)存中時,是從最低位地址開始的,首先放入最有效的字節(jié)。另一方面,對于小端字節(jié)處理器,比如 Intel 和 Alpha 處理器,首先放入的是最低效的字節(jié)。
圖 1 顯示了大端字節(jié)和小端字節(jié)處理器如何在其內(nèi)存中放置十六進制值,比如 0x89ABCDEF:
圖 1. 字節(jié)順序(字節(jié)排列順序)
出現(xiàn)字節(jié)排列順序問題的原因之一是不一致的數(shù)據(jù)引用。它經(jīng)常表現(xiàn)為由于數(shù)據(jù)元素轉(zhuǎn)換、使用聯(lián)合數(shù)據(jù)結(jié)構(gòu)或使用和操作位域?qū)е聰?shù)據(jù)類型不匹配。清單 1 說明了因為使用指針進行不一致的數(shù)據(jù)引用而引起的字節(jié)排列順序問題:
清單 1. 不一致的數(shù)據(jù)引用
int main() { int value; char *p; p = (char*) &value; value = 0x89ABCDEF; printf("%X.%X.%X.%X " p[0], p[1], p[2], p[3]); return 0; } |
![]() ![]() |
![]()
|
Linux on POWER 的開發(fā)環(huán)境
這一節(jié)將描述 Linux on POWER 開發(fā)環(huán)境的基礎(chǔ)元素,包括發(fā)行版、編譯器和 Java™ 技術(shù)的應(yīng)用。
Linux 發(fā)行版本
有兩個一流 Linux 供應(yīng)商提供了 Linux for POWER 的企業(yè)版:SUSE LINUX 和 Red Hat。雖然 Linux 社區(qū)非常倚重這兩個版本,但是它們不斷推出新的版本時,發(fā)行版和版本的差異越來越大。大部分開發(fā)人員應(yīng)該能夠順利在這兩個產(chǎn)品之一的相同代碼基礎(chǔ)上部署系統(tǒng)的軟件:
SLES11
于 2009 年初發(fā)行,Novell 的 SUSE Linux Enterprise Server 版本 11 提供新的內(nèi)核改進、虛擬化改進、管理、硬件支持和互操作性。它在數(shù)據(jù)中心包含用于處理任務(wù)關(guān)鍵型工作負(fù)載的特性和更新。SUSE Linux Enterprise Server 提供一個開源、可伸縮并且高性能的數(shù)據(jù)中心解決方案。SLES11 基于 2.6.27 內(nèi)核并提供 GCC 4.3.2、glibc 2.9 和 binutils 2.19。
SLES10 SP2
SUSE Linux Enterprise Server 版本 10 Service Pack 2 基于 Linux 2.6.16 內(nèi)核并支持 Linux on POWER 硬件的所有企業(yè)特性。該開發(fā)環(huán)境提供 GCC 4.1.2、glibc 2.4.31 和 GNU binutils 2.16.91。
RHEL5.3
Red Hat® Enterprise Linux® 5.3 基于 Linux 2.6.18 內(nèi)核并提供 GCC 4.1.2、glibc 2.5 和 binutils 2.17。相對以前的版本而言,RHEL5 包含許多改進。這些改進包括可切換的動態(tài) I/O 調(diào)試器、IPv4/IPv6 性能改進,以及改善了可伸縮性和性能的內(nèi)核 SMP 鎖改進。
RHEL4.8
Red Hat Enterprise Linux 4.8 基于 Linux 2.6.9 內(nèi)核并提供 GCC 3.4.6、glibc 2.3.4 和 binutils 2.15。不過,GCC4 包被更新到版本 4.1.2。(參考資料 部分提供一個文章鏈接,該文章在受支持的平臺上對比了 RHEL3、RHEL4 和 RHEL5 的特性)。
編譯器
與 Solaris 相似,除 GNU Compiler Collection 之外,Linux on POWER 還提供了高性能編譯器集合 —— IBM XL C/C++ 編譯器集合。XL C/C++ Advanced Edition for Linux Web 站點中有關(guān)于其許可證的詳細(xì)信息。(參考資料 部分提供相關(guān)鏈接)。下面簡單概述每組編譯器及其優(yōu)勢:
GCC
對于跨多個平臺開發(fā)的項目(其中 GCC 編譯器為原始編譯器),經(jīng)常使用 GCC 編譯器來部署 Linux on POWER 的應(yīng)用程序。對于性能不是至關(guān)重要的應(yīng)用程序尤其如此;例如,一些小的實用程序。GCC 還允許使用一些只有 GCC 才理解的代碼原型,比如 GCC 特定宏。然而,IBM XL C/C++ 編譯器中合并了其中許多 “GCC-isms”。
Advance Toolchain
對于能夠利用最新 GCC 和工具鏈技術(shù)的項目,希望繼續(xù)使用 GCC 編譯器的客戶可以使用 Advance Toolchain 包。Advance Toolchain 提供更新的 GCC 編譯器版本,并在使用 SLES10 和 RHEL5 時針對 Power 6 調(diào)用了運行時庫。在許多情況下,對于利用在 -O3 編譯級別上進行編譯的 Advance Toolchain 的 GCC 編譯應(yīng)用程序,其性能接近于在 -O3 級別上進行編譯的 IBM C/C++ 編譯器。IBM 編譯器的優(yōu)勢是性能改進和調(diào)優(yōu)存在比較大的空間,這在某些情況下尤為有用。
XL C/C++
針對 Power 系統(tǒng)的 IBM Linux XL C/C++ 編譯器已經(jīng)可用。針對 RHEL5、SLES10 和 SLES11 的 XL C/C++ 編譯器 10.1 版本已經(jīng)可用。如果您希望在更舊的 Linux 發(fā)行版(比如 SLES 9、SLES10 sp1、RHEL5 或 RHEL 4)上進行構(gòu)建,IBM 編譯器的以前版本(比如 XL C/C++ 版本 8 和 9)仍然可用。XL C/C++ 編譯器提供 GCC 的高性能代替品,以及許多其他特性。幸運的是,XL C/C++ 編譯器生成 32 位和 64 位 GNU elf 對象,它們與 GCC 編譯器生成的對象完全兼容,因為 XL C/C++ 編譯器使用與 GCC 相同的 GNU 庫、連接程序、匯編程序和 binutil。實際上,以前專門由 GCC 編譯器提供的功能已經(jīng)移植到 XL C/C++,以促進源代碼兼容性;例如,一些 GCC 宏和在線功能。但是除了兼容性,XL C/C++ 還提供了無可匹敵的性能。
已經(jīng)為 POWER 架構(gòu)開發(fā)并修改了成熟的 XL C/C++ 優(yōu)化例程并且收到了預(yù)期效果。通常對于高性能計算應(yīng)用程序,尤其是那些高度依賴浮點操作的應(yīng)用程序,使用 XL C/C++ 進行重新編譯會很有好處。
雖然 XL C/C++ for Linux on POWER 不是免費的,然而開發(fā)人員可以免費試用 60 天。詳細(xì)信息請訪問 XL C/C++ for Linux Web 站點(參考資料 部分提供相關(guān)鏈接)。
XL Fortran
如果您希望使用 Fortran 的話,針對 Power 系統(tǒng)的 IBM XL Fortran 已經(jīng)可用。針對 RHEL5、SLES10 和 SLES11 的 XL Fortran 版本 11.1 和 XL Fortran 版本 12.1 已經(jīng)可用。詳細(xì)信息請訪問 XL Fortran for Linux Web 站點(參考資料 部分提供相關(guān)鏈接)。
Binutil
在 Solaris 10 中,可以選擇使用原生構(gòu)建實用程序或使用隨 GNU 一起提供的實用程序。通過 Linux on POWER,GNU binutil 用于使用 XL C/C++ 編譯器集合和 GCC 來生成對象。GNU Binutils 站點中非常詳細(xì)地講述了 GNU binutil。(參考資料 部分提供相關(guān)鏈接)。
Java 技術(shù)
如果 Java Runtime Environment 與開發(fā)軟件平臺的 Java Developer Kit (JDK) 兼容,Java 技術(shù)允許開發(fā)人員跨多個平臺進行部署,而不用重新編譯代碼。通過 IBM Developer Kit for Linux, Java Technology Edition 版本 1.4.2、5.0 和 6.0,RHEL4、RHEL5、SLES9、SLES10 和 SLES11 都支持 Linux on POWER Java 開發(fā)。這一套開發(fā)人員套件有 32 位版本和 64 位版本,可從 IBM 免費下載(見 參考資料)。
![]() ![]() |
![]()
|
Solaris 和 Linux on POWER 之間的差別
在這一節(jié)中,將了解 Solaris 與 Linux on POWER 之間的差別,其中包括系統(tǒng)調(diào)用、信號、數(shù)據(jù)類型、makefile、編譯器選項、連接程序選項和線程庫等。
系統(tǒng)調(diào)用和庫函數(shù)
系統(tǒng)調(diào)用是用戶程序使用的接口,它可以使內(nèi)核代表調(diào)用線程或進程執(zhí)行特定函數(shù)。要執(zhí)行系統(tǒng)調(diào)用,還需要授權(quán)內(nèi)核模式的上下文切換。庫函數(shù)是普通 C 函數(shù)。它們沒有任何上下文切換資源損耗,因為它們是使用其每個進程的地址空間的一部分。一些 Solaris 系統(tǒng)調(diào)用和庫函數(shù)可能不能用于 Linux 中。發(fā)生這種情況時,可能要在 Linux 中實現(xiàn)打包器調(diào)用。
Linux on POWER 目前提供了 300 多種不同的系統(tǒng)調(diào)用。/usr/include/asm-powerpc/unistd.h 或 /usr/include/asm/unistd.h 中包含系統(tǒng)調(diào)用列表,具體目錄取決于您使用的發(fā)行版。
下面是 Solaris 和 Linux 之間不兼容的一些例子:
regexp() 和 regcmp():如果您在 Solaris 上使用 regexp() 和 regcmp(),則在 Linux 上需要將它們替換為 regexec() 和 regcomp()。
文件系統(tǒng)接口例程:Solaris 文件系統(tǒng)例程使用 vfstab 結(jié)構(gòu),函數(shù)名中包含 vfs,比如 getvfsent。Linux 提供等同的接口,但是例程使用 fstab 結(jié)構(gòu),例程名稱中包含 fs,比如 getfsent。Solaris 中的 vfstab 結(jié)構(gòu)是在 /usr/include/sys/vfstab.h 中定義的。Linux 中的 fstab 則是在 /usr/include/fstab.h 中定義的。
Device Information Library Functions (libdevinfo):libdevinfo 庫包含一組接口,用于訪問設(shè)備配置數(shù)據(jù),如主號碼和輔助號碼。標(biāo)準(zhǔn) Linux 安裝不支持這一點。
CPU Affinity:在默認(rèn)情況下,多處理器系統(tǒng)中的進程在多個 CPU 之間切換。在某些情況下,通過明確地將進程綁定到特定 CPU(分配 CPU 親和力)可以提高性能。Solaris 中 CPU 親和力的系統(tǒng)調(diào)用與 Linux 中的不同。Linux 2.6 內(nèi)核為 CPU 親和力提供了 sched_setaffinity() 和 sched_getaffinity()。有關(guān)的詳細(xì)信息,請參閱 Linux 手冊。
表 1 列出了 Solaris 系統(tǒng)調(diào)用,這些系統(tǒng)調(diào)用與 Linux 中系統(tǒng)調(diào)用的名稱、簽名不同,或在 Linux 中不可用:
表 1. Solaris 系統(tǒng)調(diào)用
Solaris | Linux | 說明 |
---|---|---|
acl、facl | N/A | 獲取或設(shè)置文件的 Access Control List (ACL) |
adjtime | N/A | 更正時間,以允許系統(tǒng)時鐘同步 |
audit | N/A | 向?qū)徲嬋罩緦懭胗涗?/td> |
auditon | N/A | 對審計進行操作 |
auditsvc | N/A | 向特定文件描述符寫入審計日志 |
getacct、putacct、wracct | N/A | 獲取、放入或?qū)懭霐U展報告數(shù)據(jù) |
getaudit、setaudit、getaudit_addr、setaudit_addr | N/A | 獲取和設(shè)置進程審計信息 |
getauid、setauid | N/A | 獲取和設(shè)置用戶審計身份 |
getdents | getdents** | 讀取目錄條目,并以單獨格式將其放入文件系統(tǒng)中。Linux 中的 Dirent 結(jié)構(gòu)與 Solaris 中的不同 |
getmsg、getpmsg | N/A | 獲取數(shù)據(jù)流中的下一條消息 |
getpflags、setpflags | N/A | 獲取或設(shè)置流程標(biāo)記 |
getppriv、setppriv | N/A | 獲取或設(shè)置進程標(biāo)志 |
getustack、setustack | N/A | 檢索或更改 per-LWP 堆棧邊界信息 |
issetugid | N/A | 確定當(dāng)前可執(zhí)行程序是在運行 setuid 還是在運行 setgid |
llseek | _llseek | 移動擴展讀/寫文件指針 |
_lwp_cond_signal、_lwp_cond_broadcast | N/A | 對條件變量發(fā)送信號 |
_lwp_cond_wait、_lwp_cond_timedwait、_lwp_cond_reltimedwaid | N/A | 等待條件變量 |
_lwp_info | N/A | 返回單個 LWP 的時間核算信息 |
_lwp_kill | N/A | 向 LWP 發(fā)送信號 |
_lwp_mutex_lock、_lwp_mutex_unlock、_lwp_mutex_trylock | N/A | 互斥 |
_lwp_self | N/A | 獲取 LWP 標(biāo)識符 |
_lwp_sema_wait、_lwp_sema_trywait、_lwp_sema_init、_lwp_sema_post | N/A | 信號燈操作 |
_lwp_suspend、_lwp_continue | N/A | 繼續(xù)或暫停 LWP 執(zhí)行 |
memcntl | N/A | 內(nèi)存管理控制 |
meminfo | N/A | 提供內(nèi)存信息 |
mount | mount* | 裝載文件系統(tǒng)。Solaris 中此系統(tǒng)調(diào)用的簽名與 Linux 的不同 |
msgids | N/A | 發(fā)現(xiàn)所有消息隊列標(biāo)識符 |
msgrcv | msgrcv* | 消息接收操作。Linux 在其一個參數(shù)中使用 struct msgbuf 類型 |
msgsnap | N/A | 消息隊列快照操作 |
msgsnd | msgsnd* | 消息發(fā)送操作。Linux 在其一個參數(shù)中使用 struct msgbuf 類型 |
ntp_adjtime | N/A | 調(diào)整本地時鐘參數(shù) |
ntp_gettime | N/A | 獲取本地時鐘值 |
open、openat | open* | 打開文件。openat() 不能在 Linux 中使用 |
pcsample | N/A | 程序執(zhí)行時間配置文件 |
p_online | N/A | 返回或更改處理器操作狀態(tài) |
priocntl | N/A | 進程調(diào)度器控制 |
priocntlset | N/A | 一般化的進程調(diào)度器控制 |
processor_bind | sched_setaffinity | 將 LWP 綁定到處理器 |
processor_info | N/A | 確定處理器類型和狀態(tài) |
pset_bind | N/A | 將 LWP 綁定到處理器集合 |
pset_create、pset_destroy、pset_assign | N/A | 管理處理器集合 |
pset_info | N/A | 獲取處理器集合的信息 |
pset_list | N/A | 獲取處理器集合的列表 |
pset_setattr、pset_getattr | N/A | 設(shè)置或獲取處理器集合屬性 |
putmsg、putpmsg | N/A | 發(fā)送流消息 |
rename、renameat | rename* | 更改文件名。Linux 沒有 renameat() 函數(shù) |
resolvepath | N/A | 分析路徑名稱的所有符號鏈接 |
semids | N/A | 發(fā)現(xiàn)所有信號燈標(biāo)識符 |
setrctl、getrctl | N/A | 設(shè)置或獲取資源控制值 |
settaskid、gettaskid、getprojid | N/A | 設(shè)置或獲取任務(wù)或項目 ID |
shmids | N/A | 發(fā)現(xiàn)所有共享內(nèi)存標(biāo)識符 |
sigsend、sigsendset | N/A | 向處理器或處理器組發(fā)送信號 |
__sparc_utrap_install | N/A | 安裝 SPARC V9 用戶陷阱處理程序 |
fstatat | N/A | 獲取文件狀態(tài) |
swapctl | N/A | 管理交換空間 |
uadmin | N/A | 管理控制 |
unlink、unlinkat | unlink* | 刪除目錄條目。Linux 沒有 unlinkat() 函數(shù) |
futimesat | N/A | 設(shè)置文件訪問權(quán)和修改時間。它分析關(guān)于 fildes 參數(shù)的路徑 |
waitid | N/A | 等待子進程來更改狀態(tài) |
yield | sched_yield | 放棄對其他輕量級進程的執(zhí)行 |
信號
信號用于向進程或線程通知特定事件。Linux 支持 POSIX 標(biāo)準(zhǔn)信號和 POSIX 實時信號。每個信號都有惟一名稱和相應(yīng)的信號編號。例如,對于 Solaris,SIGSTOP 的信號編號是 23,但是對于 Linux on POWER,其信號編號則為 19。/usr/include/bits/signum 中可以找到 Linux 上的信號編號定義。
對于所有可能的信號,系統(tǒng)會定義出現(xiàn)信號時執(zhí)行的默認(rèn)操作:
Terminate:默認(rèn)操作是終止進程。
Ignore:默認(rèn)操作是忽略信號。
Core:默認(rèn)操作是終止進程并轉(zhuǎn)儲內(nèi)核。
Stop:默認(rèn)操作是停止進程。
有關(guān) Linux 信號的完整列表,包括每個信號的簡短描述及發(fā)出信號時的默認(rèn)行為,請通過調(diào)用下列命令查看 Section 7 中的信號手冊:# man 7 signal。對于 Linux,請注意以下事項:
SIGABRT 和 SIGIOT 是相同的。
SIGCLD 和 SIGCHLD 是相同的。
SIGPOLL 和 SIGIO 是相同的。
對于 Linux,SIGPWR 的默認(rèn)操作是終止進程,而在 Solaris 中則忽略該操作。
表 2 顯示了 Solaris 支持但 Linux on POWER 不支持的信號:
表 2. Solaris 支持的信號
名稱 | 默認(rèn)操作 | 說明 |
---|---|---|
SIGEMT | core | 模擬陷阱 |
SIGWAITING | ignore | 線程庫使用的并發(fā)信號 |
SIGLWP | ignore | 線程庫使用的 Inter-LWP 信號 |
SIGFREEZE | ignore | 檢查點暫停 |
SIGTHAW | ignore | 檢查點繼續(xù) |
SIGCANCEL | ignore | 線程庫使用的取消信號 |
SIGLOST | ignore | 資源丟失(運行于 Sparc 上的 Linux 支持該項) |
SIGXRES | ignore | 資源控制超出 |
在 Soalris 和 Linux 上,sigset_t 的定義有所不同。在 Linux 上,它在 /usr/include/bits/sigset.h 中定義為:
清單 2. 如何在 Linux 上定義 sigset_t
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) typedef struct { unsigned long int __val[_SIGSET_NWORDS]; } __sigset_t; #endif |
在 Solaris 上,它在 /usr/include/sys/signal.h 中定義為:
清單 3. 如何在 Solaris 上定義 sigset_t
typedef struct { /* signal set type */ unsigned int __sigbits[4]; } sigset_t; |
基本數(shù)據(jù)類型和對齊
系統(tǒng)中可以有兩種不同的數(shù)據(jù)類型:基本數(shù)據(jù)類型 和衍生數(shù)據(jù)類型。
基本數(shù)據(jù)類型是 C 和 C++ 語言規(guī)范定義的所有數(shù)據(jù)類型。表 3 對 Linux on POWER 和 Solaris 中的基本數(shù)據(jù)類型進行了比較(值以字節(jié)為單位):
表 3. 基本數(shù)據(jù)類型
基本類型 | Linux on POWER, ILP32 | Linux on POWER, LP64 | Solaris, ILP32 | Solaris, LP64 |
---|---|---|---|---|
_Bool,bool | 1 | 1 | 1 | 1 |
char | 1 | 1 | 1 | 1 |
wchar_t | 2 | 4 | 4 | 4 |
short | 2 | 2 | 2 | 2 |
int | 4 | 4 | 4 | 4 |
float | 4 | 4 | 4 | 4 |
long | 4 | 8 | 4 | 8 |
pointer | 4 | 8 | 4 | 8 |
long long | 8 | 8 | 8 | 8 |
double | 8 | 8 | 8 | 8 |
long double | 16* | 16* | 16 | 16 |
*從 Red Hat Enterprise Linux 5 (RHEL5) 和 SUSE Linux Enterprise Server 10 (SLES10) 開始,在 Linux on POWER 中 long double 的默認(rèn)大小是 128 位。在 RHEL5 或 SLES10 之前,如果 XL 編譯器中使用了編譯器選項 -qldbl128,那么其大小可以增加到 128 位。
當(dāng)在平臺之間或在 32 位和 64 位模式之間移植應(yīng)用程序時,需要考慮不同環(huán)境中可用對齊設(shè)置之間的差別,以避免可能發(fā)生的性能下降和數(shù)據(jù)損壞。對于 IBM XL C/C++ 編譯器,集合(C/C++ 結(jié)構(gòu)/聯(lián)合及 C++ 類)內(nèi)的每個數(shù)據(jù)類型將根據(jù) linuxppc 或 bit-packed 規(guī)則沿字節(jié)邊界對齊(使用 -qalign 選項),其中 linuxppc 為默認(rèn)值。linuxppc 使用 GNU C/C++ 對齊規(guī)則維護與 GNU C/C++ 對象的二進制兼容性。
表 4 用顯示了 linuxppc 和 bit-packed 規(guī)則的對齊值:
表 4. 對齊值
數(shù)據(jù)類型 | linuxppc | bit-packed |
---|---|---|
_Bool,bool | 1 | 1 |
char | 1 | 1 |
wchar_t (32-bit) | 2 | 1 |
wchar_t (64-bit) | 4 | 1 |
int | 4 | 1 |
short | 2 | 1 |
long (32-bit) | 4 | 1 |
long (64-bit) | 8 | 1 |
long long | 8 | 1 |
float | 4 | 1 |
double | 8 | 1 |
long double | 16 | 1 |
SPARC 平臺通常要求數(shù)據(jù)對齊遵循相等的數(shù)據(jù)大?。? 字節(jié)類型必須在 2 字節(jié)區(qū)域內(nèi),4 字節(jié)類型必須在 4 字節(jié)區(qū)域內(nèi)。因此,當(dāng)您從 Solaris 移植到 Linux 時,必須特別注意 Solaris 和 Linux 之間的不同大小的數(shù)據(jù)類型。
系統(tǒng)衍生數(shù)據(jù)類型
衍生數(shù)據(jù)類型是現(xiàn)有基本類型或其他衍生類型的衍生物或結(jié)構(gòu)。根據(jù)使用的數(shù)據(jù)模型(32 位或 64 位)和硬件平臺,系統(tǒng)衍生數(shù)據(jù)類型可以具有不同的字節(jié)大小。表 5 顯示了 Linux 中的一些衍生數(shù)據(jù)類型,它們與 Solaris 中的那些衍生數(shù)據(jù)類型不同:
表 5. 衍生數(shù)據(jù)類型
數(shù)據(jù)類型 | Solaris ILP32 | Solaris LP64 | Linux on POWER ILP32 | Linux on POWER LP64 |
---|---|---|---|---|
gid_t | long | int | unsigned int | unsigned int |
mode_t | unsigned long | unsigned int | unsigned int | unsigned int |
pid_t | long | int | int | int |
uid_t | long | int | unsigned int | unsigned int |
wint_t | long | int | unsigned int | unsigned int |
GNU Make 與 Solaris Make
如果在源平臺中使用 Solaris Make,為了在 Linux 中使用 GNU Make,需要修改 makefile。要獲得 Solaris Make 和 GNU Make 之間差別的詳細(xì)信息,請參閱 IBM 紅皮書 “AIX 5L Porting Guide” 的第 6 章。
編譯器選項
表 6 列出了 SUN Studio C/C++ 編譯器廣泛使用的編譯器選項,以及 GNU Compiler Collection 和 IBM XL 編譯器的等同選項:
表 6. 編譯器選項
Sun Studio 選項 | GNU GCC 選項 | XL C/C++ 選項 | 說明 |
---|---|---|---|
-# | -v | -v | 指示編譯器報告編譯進度信息 |
-### | -### | -# | 跟蹤編譯,而不調(diào)用任何東西 |
-dn | -static | -qstaticlink | 指定靜態(tài)鏈接 |
-dy | (Default) | (Default) | 指定動態(tài)鏈接 |
-G | -shared | -qmkshrobj | 生成共享對象,而不是生成動態(tài)鏈接可執(zhí)行程序 |
-xmemalign | -malign-natural、 -malign-power |
-qalign | 指定最大假定內(nèi)存對齊(memory alignment),以及未對齊數(shù)據(jù)訪問的行為 |
-xO1、-xO2、-xO3、-xO4、-xO5 | -O、-O2、-O3 | -O、-O2、-O3、-O4、-O5 | 編譯過程中在所有級別上優(yōu)化代碼 |
-KPIC | -fPIC | -qpic=large | 生成位置無關(guān)代碼以用于共享庫中(大模型) |
-Kpic | -fpic | -qpic=small | 生成位置無關(guān)代碼以用于共享庫中(小模型) |
-mt | -pthread | Use _r invocation mode | 編譯和鏈接多線程代碼 |
-R dirlist | -Wl、-rpath、dirlist | -Wl、-rpath、dirlist | 構(gòu)建可執(zhí)行文件的動態(tài)庫搜索路徑 |
-xarch | -mcpu、-march | -qarch、-qtune | 指定目標(biāo)架構(gòu)指令集合 |
XL C/C++ 編譯器支持 GNU 編譯器選項的一部分,從而有利于移植使用 GCC 和 g++ 編譯器開發(fā)的應(yīng)用程序。將 gxlc 或 gxlc++ 調(diào)用命令與 GNU 編譯器選項一起使用來啟用該支持。這些調(diào)用命令使用純文本配置文件來控制 GNU-to-XL C/C++ 選項映射和默認(rèn)值。您可以根據(jù)需求更改這些配置文件。參考 XL 編譯器手冊更多地了解 gxlc 和 gxlc++。
Solaris 線程和 NPTL
這一節(jié)將說明開發(fā)人員將多線程應(yīng)用程序從 Solaris 遷移到 Linux 時會遇到的問題。
Solaris 支持兩種線程實現(xiàn):Solaris 線程和 POSIX 線程(pthreads)。有一些函數(shù)由 Solaris 線程 API 實現(xiàn),而不是由 pthreads API 實現(xiàn),反之亦然。對于那些符合以上情況的函數(shù),關(guān)聯(lián)的參數(shù)可能不符合。下列是僅受 Solaris 線程 API 支持的特性:
創(chuàng)建守護進程線程的能力。守護進程線程不影響進程退出狀態(tài)。進程可以通過調(diào)用 exit() 退出,也可以通過讓進程中的每個非守護進程線程調(diào)用 thr_exit() 來退出。
使用 thr_suspend() 和 thr_continue() 來暫?;蚶^續(xù)線程執(zhí)行的能力。注意 thr_suspend() 可以暫停目標(biāo)線程,而不涉及線程可能擁有的鎖。如果暫停線程調(diào)用某一個函數(shù),而該函數(shù)需要已暫停的目標(biāo)線程所擁有的鎖,那么就會出現(xiàn)死鎖。
允許線程等待進程中任何未檢驗出的線程終止的能力。當(dāng) thr_join() 的第一個參數(shù)設(shè)為 0 時就會這樣。如果將 pthread_join() 的第一個參數(shù)設(shè)為 0,程序?qū)⒁蚨五e誤而終止。
表 7 將關(guān)鍵 Solaris 線程函數(shù)與 pthreads 函數(shù)進行了比較。對于其他 Solaris 線程函數(shù),請參閱 SUN 的 “Multithreaded Porting Guide”(見 參考資料)。
表 7. 線程和 pthreads 函數(shù)
Solaris 線程 API | Linux POSIX 線程 API | 說明 |
---|---|---|
thr_create() | pthread_create() | 創(chuàng)建新的控制線程 |
thr_exit() | pthread_exit() | 終止執(zhí)行調(diào)用線程 |
thr_join() | pthread_join() | 暫停調(diào)用線程,直到目標(biāo)線程完成 |
thr_kill() | pthread_kill() | 向其他線程發(fā)送信號 |
thr_self() | pthread_self() | 返回調(diào)用進程的線程 ID |
thr_yield() | sched_yield() | 用其他線程替換當(dāng)前線程 |
thr_getprio() | pthread_getschedparam() | 獲取線程的優(yōu)先級參數(shù) |
thr_setprio() | pthread_setschedparam() | 修改線程的優(yōu)先級參數(shù) |
thr_getspecific() | pthread_getspecific() | 將新的線程特定值綁定到特定鍵 |
thr_setspecific() | pthread_setspecific() | 將新的線程特定值綁定到特定鍵 |
thr_getconcurrency() | pthread_getconcurrency() | 獲取線程并發(fā)級別 |
thr_setconcurrency() | pthread_setconcurrency() | 設(shè)置線程并發(fā)級別 |
thr_sigsetmask() | pthread_sigmask() | 更改或檢查調(diào)用線程的信號掩碼 |
thr_keycreate() | pthread_key_create() | 創(chuàng)建確定線程特定數(shù)據(jù)的位置的鍵 |
N/A | pthread_key_delete() | 刪除確定線程特定數(shù)據(jù)的位置的鍵 |
thr_suspend() | N/A | 暫停執(zhí)行指定的線程 |
thr_continue() | N/A | 繼續(xù)執(zhí)行暫停的線程 |
fork1() | fork() | 常規(guī)分支 |
forkall() | N/A | 復(fù)制所有分支 |
在 Solaris 9 及其更早的版本中,fork() 的行為與 POSIX 線程中 fork() 的行為不同。在 POSIX 線程中,fork() 創(chuàng)建新的進程,復(fù)制子進程中的全部地址空間。不過,它只復(fù)制子進程中的調(diào)用線程。Solaris 線程 API 還提供復(fù)制所有分支語義的 forkall()。該函數(shù)復(fù)制子進程中的地址空間和所有線程。POSIX 線程標(biāo)準(zhǔn)不支持這個特性。
有一些 POSIX 線程例程在 Solaris 中可以實現(xiàn),但在 Linux 中卻無法實現(xiàn),反之亦然。表 8 列出了這些例程:
表 8. POSIX 線程例程
例程 | Solaris | Linux |
---|---|---|
pthread_cond_reltimedwait_np | y | n |
pthread_mutexattr_getrobust_np | y | n |
pthread_mutexattr_setrobust_np | y | n |
pthread_mutex_consistent_np | y | n |
pthread_mutex_reltimedlock_np | y | n |
pthread_rwlock_reltimedrdlock_np | y | n |
pthread_rwlock_reltimedwrlock_np | y | n |
pthread_attr_getaffinity_np | n | y |
pthread_attr_setaffinity_np | n | y |
pthread_cleanup_pop_restore_np | n | y |
pthread_cleanup_push_defer_np | n | y |
pthread_getattr_np | n | y |
pthread_kill_other_threads_np | n | y |
pthread_rwlockattr_getkind_np | n | y |
pthread_rwlockattr_setkind_np | n | y |
pthread_timedjoin_np | n | y |
pthread_tryjoin_np | n | y |
2.6 版之前發(fā)行的所有 Linux 版本中的 Linux 線程庫都稱為 LinuxThreads。該庫自 glibc 2.0 以來已經(jīng)得到 GNU C 庫支持,而且在很大程度上與 POSIX 是兼容的。從 2.6 內(nèi)核開始,引入了新的經(jīng)過改善的線程庫,稱為 Native POSIX Threading Library(NPTL)。該實現(xiàn)在 LinuxThreads 之上提供了顯著的性能提高。NPTL 與 POSIX 規(guī)范的兼容性也強于 LinuxThreads 包與 POSIX 規(guī)范的兼容性。然而,只使用 2.6 內(nèi)核并不意味著就使用了 NPTL。發(fā)出下列命令可以查看正在使用的 POSIX 實現(xiàn):
$ getconf GNU_LIBPTHREAD_VERSION
NPTL 實現(xiàn)一對一線程模型,在該模型中,用戶線程與內(nèi)核線程之間存在一對一的關(guān)系。NPTL 還實現(xiàn)進程間 POSIX 同步原語。特別是線程選項 PTHREAD_PROCESS_SHARED 現(xiàn)在已受支持。在默認(rèn)情況下,創(chuàng)建每個線程時,detachstate 屬性被設(shè)為 PTHREAD_CREATE_JOINABLE,調(diào)用策略設(shè)為 SCHED_OTHER,而且沒有用戶提供的堆棧。
如果 Solaris 應(yīng)用程序使用 POSIX 線程 API,那么將其移植到 Linux 會非常簡單。注意,即使使用 GCC,Solaris 也不支持 NPTL。表 9 顯示了 Linux 中 POSIX 線程屬性的默認(rèn)值:
表 9. Linux 中 POSIX 線程屬性的默認(rèn)值
屬性 | 默認(rèn)值 |
---|---|
scope | PTHREAD_SCOPE_SYSTEM |
detachstate | PTHREAD_CREATE_JOINABLE |
schedparam | 0 |
inhiritsched | PTHREAD_EXPLICIT_SCHED |
schedpolicy | SCHED_OTHER |
雖然許多應(yīng)用程序?qū)?2.4 內(nèi)核遷移到 2.6,而無需重新編譯,但是增加 NPTL 可能需要在多線程應(yīng)用程序中進行少量的修改。關(guān)于如何通過使用 LinuxThreads 將應(yīng)用程序遷移到 NPTL 超出了本文的范圍。LinuxDevices.com 上的文章 “Migrating to Linux kernel 2.6” 提供其他相關(guān)信息(見 參考資料)。
![]() ![]() |
![]()
|
性能調(diào)優(yōu)
一旦在 Linux 中移植并成功執(zhí)行了代碼,需要完成性能監(jiān)控和性能調(diào)優(yōu),以確保移植的代碼在目標(biāo)平臺上可以正常執(zhí)行。這一節(jié)將提供 Linux on POWER 中可以使用的工具列表,幫助您完成以上操作。
常用性能調(diào)優(yōu)工具
兩個常用的工具(sysstat 包 和 nmon)使得性能監(jiān)控和調(diào)優(yōu)更加容易:
sysstat 包包含用于基礎(chǔ)性能監(jiān)控的通用擴展工具,包括 mpstat、iostat 和 sar 等工具。
nmon 將各種經(jīng)典的系統(tǒng)監(jiān)控工具集成到一個一站式的數(shù)據(jù)收集工具中。此外,還包含許多方便使用的后期處理插件,可用于收集、繪制和合并信息。
OProfile
Oprofile 基于硬件相關(guān)事件(比如緩存遺漏或 CPU 周期)提供代碼的配置文件。例如,Oprofile 可以幫助確定是哪個源例程導(dǎo)致大部分緩存遺漏。Oprofile 使用包括 IBM POWER4?、POWER5?、POWER6? 和 PowerPC? 970 在內(nèi)的許多 CPU 中提供的硬件性能計數(shù)器。有關(guān)的