王立杰,胡先浪,張大方
(江蘇自動(dòng)化研究所 電子設(shè)備事業(yè)部,連云港 222006)
隨著龍芯3A3000、申威421 和飛騰1500A 等國(guó)產(chǎn)多核處理器的投入使用以及中標(biāo)麒麟、深度、銀河麒麟等國(guó)產(chǎn)操作系統(tǒng)的快速推廣應(yīng)用,國(guó)產(chǎn)處理器與國(guó)產(chǎn)操作系統(tǒng)任意兩兩組合構(gòu)成了目前國(guó)產(chǎn)平臺(tái)多樣化的生態(tài)格局[1].目前在國(guó)產(chǎn)平臺(tái)上開(kāi)發(fā)并發(fā)程序經(jīng)常采用多線(xiàn)程技術(shù)來(lái)實(shí)現(xiàn),每個(gè)線(xiàn)程利用單個(gè)CPU 核的計(jì)算能力,多個(gè)線(xiàn)程就可以更好地利用整個(gè)CPU 的多核處理能力來(lái)實(shí)現(xiàn)復(fù)雜的功能[2].但是,線(xiàn)程需要通過(guò)信號(hào)量、互斥鎖、臨界區(qū)等并發(fā)資源來(lái)實(shí)現(xiàn)相互之間的同步.多線(xiàn)程同步機(jī)制選擇必須謹(jǐn)慎,因?yàn)椴磺‘?dāng)?shù)娜蝿?wù)同步可能導(dǎo)致一段時(shí)間內(nèi)一個(gè)任務(wù)運(yùn)行而其他任務(wù)阻塞的情況,使得程序性能下降很多.多個(gè)線(xiàn)程在使用共享資源時(shí),就會(huì)發(fā)生競(jìng)爭(zhēng).如果程序設(shè)計(jì)的不好,則程序會(huì)發(fā)生死鎖[3,4].
當(dāng)前,在國(guó)產(chǎn)平臺(tái)中使用圖形化集成開(kāi)發(fā)環(huán)境開(kāi)發(fā)多線(xiàn)程并發(fā)程序時(shí),由于缺少良好的并發(fā)性能分析工具,使得用戶(hù)難以分析程序中的并發(fā)資源使用情況,以及判斷程序中可能存在的死鎖問(wèn)題,從而影響了應(yīng)用程序的開(kāi)發(fā).開(kāi)發(fā)面向國(guó)產(chǎn)平臺(tái)的并發(fā)性能分析插件,一方面能夠讓用戶(hù)了解程序動(dòng)態(tài)運(yùn)行過(guò)程和并發(fā)資源的使用情況,對(duì)自己的程序進(jìn)行優(yōu)化;另一方面,可以解決程序中因?yàn)椴l(fā)資源爭(zhēng)用而導(dǎo)致的死鎖問(wèn)題.
本文提出的Qt Creator 下并發(fā)性能分析插件可以實(shí)時(shí)監(jiān)控程序不同線(xiàn)程的鎖、信號(hào)量及同步操作,記錄相關(guān)行為信息,同時(shí)采集程序執(zhí)行過(guò)程中的上下文切換、cache 命中率等反映程序執(zhí)行性能的數(shù)據(jù).插件提供了性能數(shù)據(jù)分析和死鎖檢測(cè)的可視化界面,便于上層開(kāi)發(fā)理解和分析.
英特爾開(kāi)發(fā)的Vtune Amplifier[5]工具支持對(duì)并發(fā)應(yīng)用程序的性能進(jìn)行分析,使用線(xiàn)程分析工具可以獲取處理器計(jì)算能力使用效率,以及在線(xiàn)程運(yùn)行時(shí)定位由于線(xiàn)程同步時(shí)的資源爭(zhēng)用導(dǎo)致的處理器效率低的問(wèn)題,工具使用有效CPU 利用率指標(biāo)作為線(xiàn)程效率的主要衡量指標(biāo).Vtune 功能比較完善,但使用費(fèi)用較高,僅支持Intel 的處理器.
微軟開(kāi)發(fā)的Visual Studio 可以通過(guò)性能資源管理器分析并發(fā)程序中的信號(hào)量、臨界區(qū)等共享資源的同步與互斥時(shí)間開(kāi)銷(xiāo),包括等待時(shí)間和使用時(shí)間,可以查看爭(zhēng)用最激烈的資源和代碼段等信息,進(jìn)一步優(yōu)化并發(fā)程序性能,目前僅支持x86 平臺(tái)[6].
Helgrind 是一個(gè)Linux 平臺(tái)下的一個(gè)開(kāi)源并發(fā)性能分析工具[7],用于檢測(cè)使用POSIX pthreads 線(xiàn)程原語(yǔ)的C/C ++程序中的同步錯(cuò)誤.Helgrind 可以檢測(cè)錯(cuò)誤使用POSIX threads API、加鎖順序?qū)е碌乃梨i和數(shù)據(jù)爭(zhēng)用三類(lèi)錯(cuò)誤.Helgrind 是基于命令行的工具,沒(méi)有友好的人機(jī)界面,同時(shí)使用該工具會(huì)引入較大的系統(tǒng)開(kāi)銷(xiāo).
目前國(guó)產(chǎn)平臺(tái)下大量采用Qt Creator 作為程序開(kāi)發(fā)工具,在Qt Creator 下缺乏一種低開(kāi)銷(xiāo)的可視化并發(fā)性能分析插件來(lái)輔助應(yīng)用開(kāi)發(fā).
Qt Creator 是一種跨平臺(tái)的集成開(kāi)發(fā)環(huán)境[8],它采用微內(nèi)核架構(gòu),所有的功能都是通過(guò)插件實(shí)現(xiàn),其結(jié)構(gòu)如圖1所示.
圖1 Qt Creator 架構(gòu)示意圖
Qt Creator 最主要的功能是在名為Core 的插件中實(shí)現(xiàn)的.Core 插件暴露了大量核心對(duì)象如主窗口本身、視圖、導(dǎo)航面板、大綱、文件系統(tǒng)、菜單等,這些對(duì)象構(gòu)成了基礎(chǔ)的集成開(kāi)發(fā)環(huán)境.Core 插件也提供了大量與環(huán)境進(jìn)行交互的接口,比如IEditor、IDocument、IOptionsPage、IEditorToolBar 等.插件管理器管理所有的插件,包括讀取插件描述文件,解決插件依賴(lài),加載插件,按正確的順序初始化插件等.插件管理器提供插件合作機(jī)制以支持插件相互依賴(lài),共同工作.
在以國(guó)產(chǎn)處理器與國(guó)產(chǎn)操作系統(tǒng)為核心的國(guó)產(chǎn)平臺(tái)上開(kāi)發(fā)面臨最大的問(wèn)題就是生態(tài)鏈不完善.為了彌補(bǔ)國(guó)產(chǎn)平臺(tái)上缺少并發(fā)性能分析工具的問(wèn)題,我們?cè)O(shè)計(jì)了面向國(guó)產(chǎn)平臺(tái)的并發(fā)性能分析方案,該方案分為并發(fā)事件監(jiān)控、性能數(shù)據(jù)采集和分析插件界面三個(gè)模塊,其整體構(gòu)成如圖2所示.并發(fā)事件監(jiān)控模塊主要通過(guò)接管操作系統(tǒng)并發(fā)相關(guān)接口API,實(shí)時(shí)捕獲并發(fā)事件.性能數(shù)據(jù)采集與分析模塊獲取并發(fā)事件發(fā)生時(shí)的線(xiàn)程、上下文和時(shí)間戳等信息,并根據(jù)采集到的數(shù)據(jù)進(jìn)行死鎖分析.分析插件界面主要包含多視圖并發(fā)性能數(shù)據(jù)展示界面、人機(jī)友好的數(shù)據(jù)視圖切換和可定位至源代碼的死鎖檢測(cè)界面等.
目前在國(guó)產(chǎn)Linux 平臺(tái)上,常用于線(xiàn)程同步的并發(fā)操作主要有POSIX 信號(hào)量和pthreads[9],需要監(jiān)控的詳細(xì)事件如表1所示.
表1 監(jiān)聽(tīng)事件列表
1)信號(hào)量(semaphore)是一種用于提供不同進(jìn)程間或一個(gè)給定進(jìn)程的不同線(xiàn)程間同步手段的原語(yǔ).信號(hào)量的使用主要是用來(lái)保護(hù)共享資源,使得資源在一個(gè)時(shí)刻只有一個(gè)進(jìn)程(線(xiàn)程)所擁有.信號(hào)量的值為正的時(shí)候,說(shuō)明它空閑.所測(cè)試的線(xiàn)程可以鎖定而使用它.若為0,說(shuō)明它被占用,測(cè)試的線(xiàn)程要進(jìn)入睡眠隊(duì)列中,等待被喚醒.
2)pthreads 庫(kù)除了提供了一套符合POSIX 標(biāo)準(zhǔn)的線(xiàn)程創(chuàng)建、運(yùn)行、銷(xiāo)毀的實(shí)現(xiàn)機(jī)制外,還提供了符合POSIX 標(biāo)準(zhǔn)的線(xiàn)程同步庫(kù).在pthreads 庫(kù)中,主要提供了互斥體(mutex)與條件變量(conditional variable)給線(xiàn)程進(jìn)行同步.互斥體可以被不同的線(xiàn)程用來(lái)同步對(duì)一個(gè)共享資源的訪(fǎng)問(wèn),例如不允許對(duì)一個(gè)共享資源寫(xiě)入的同時(shí)進(jìn)行讀取.而條件變量則起到了補(bǔ)充性的作用,即可以用來(lái)通知其它的線(xiàn)程某個(gè)共享資源的狀態(tài)已經(jīng)發(fā)生了變化.
為了不修改系統(tǒng)庫(kù)和應(yīng)用程序,本文使用了Linux 共享庫(kù)的LD_PRELOAD 機(jī)制接管POSIX 并發(fā)相關(guān)接口,在用戶(hù)進(jìn)程載入時(shí)首先載入性能分析庫(kù).在性能分析庫(kù)中定義了與POSIX 并發(fā)接口完全相同的接口,在接口實(shí)現(xiàn)里首先調(diào)用真正的POSIX 接口,然后再執(zhí)行監(jiān)控模塊,在監(jiān)控模塊里收集并發(fā)事件信息,從而實(shí)現(xiàn)了監(jiān)控過(guò)程的非侵入.
在對(duì)程序進(jìn)行并發(fā)性能分析時(shí),只是監(jiān)控并發(fā)事件的發(fā)生還不能有效幫助用戶(hù)開(kāi)發(fā)多線(xiàn)程并發(fā)程序.用戶(hù)需要了解發(fā)生并發(fā)事件時(shí)的所有關(guān)鍵信息,包括事件發(fā)生的時(shí)間、所屬線(xiàn)程和發(fā)生并發(fā)事件時(shí)的上下文信息,以便精確定位發(fā)生性能瓶頸甚至死鎖的具體原因.在3.1 節(jié)中定義的監(jiān)控模塊中利用系統(tǒng)函數(shù)可以方便的采集到時(shí)戳和所屬線(xiàn)程信息.為了獲取發(fā)生并發(fā)事件時(shí)的上下文信息,本文使用了第三方庫(kù)libunwind[10],該工具定義了可移植的、高效的C 編程接口來(lái)獲取程序的調(diào)用棧.獲取上下文信息基本流程圖如圖3所示.
圖2 面向國(guó)產(chǎn)平臺(tái)的并發(fā)性能分析插件總體框架
利用二進(jìn)制文件中的調(diào)試信息將調(diào)用棧中的符號(hào)映射為源代碼中的行號(hào),從而能精確定位發(fā)生并發(fā)事件在源代碼中的位置,進(jìn)而為性能優(yōu)化提供依據(jù).
除了并發(fā)事件以外,程序執(zhí)行時(shí)的某些系統(tǒng)參數(shù)在一定程度上也反映了程序執(zhí)行的并發(fā)性能,如Cache 命中情況,上下文切換次數(shù)等.為了更全面、低開(kāi)銷(xiāo)的獲取程序并發(fā)性能態(tài)勢(shì),本文借助硬件性能計(jì)數(shù)器PMU 獲取性能數(shù)據(jù).由于國(guó)產(chǎn)處理器會(huì)根據(jù)自身體系結(jié)構(gòu)特征定義不同的硬件事件組合,不同處理器的硬件性能計(jì)數(shù)器參數(shù)均不相同[11,12].考慮到事件監(jiān)測(cè)和性能分析的需求,不同處理器的事件集合往往在功能上會(huì)有交集.通過(guò)將國(guó)產(chǎn)處理器共有事件特性抽象出來(lái),設(shè)計(jì)統(tǒng)一的PMU 訪(fǎng)問(wèn)接口,將不同處理器中存在功能共性的事件抽象成接口專(zhuān)用的事件集并同統(tǒng)一命名,簡(jiǎn)化PMU 訪(fǎng)問(wèn)過(guò)程,其基本架構(gòu)如圖4所示.
基于上述采集到的并發(fā)性能數(shù)據(jù),根據(jù)死鎖形成的條件對(duì)程序是否存在死鎖進(jìn)行分析.死鎖指的是在并行程序中,多個(gè)并行任務(wù)形成相互等待的狀態(tài),導(dǎo)致這些任務(wù)均無(wú)法繼續(xù)執(zhí)行.死鎖發(fā)生的條件被稱(chēng)為Coffman 條件,它們包括以下4 條[13]:
(1)互斥.即必然有某個(gè)共享資源只能被單個(gè)任務(wù)使用,而不能被多個(gè)任務(wù)并發(fā)訪(fǎng)問(wèn);
圖3 獲取上下文信息流程
圖4 面向國(guó)產(chǎn)平臺(tái)的PMU 統(tǒng)一訪(fǎng)問(wèn)架構(gòu)
(2)任務(wù)處在持有一個(gè)共享資源,同時(shí)又要求擁有其他共享資源的狀態(tài);
(3)共享資源無(wú)法被搶占(preempt),只能由擁有者主動(dòng)放棄獨(dú)占才能被釋放;
(4)循環(huán)等待.即一組任務(wù)每個(gè)都持有一個(gè)共享資源,同時(shí)在等待其他任務(wù)已經(jīng)持有的共享資源.
因此,對(duì)于死鎖的檢測(cè),主要也是針對(duì)上述4 個(gè)條件進(jìn)行.針對(duì)第一個(gè)條件,在上述同步對(duì)象中,pthread 互斥體與POSIX 信號(hào)量均產(chǎn)生了互斥,因此滿(mǎn)足第一個(gè)條件.而一旦持有相應(yīng)的同步對(duì)象,也只有等待持有者主動(dòng)放棄才可以釋放,因此也滿(mǎn)足第三個(gè)條件.所以只需要檢測(cè)第二個(gè)條件與第四個(gè)條件即可.
根據(jù)采集到的性能數(shù)據(jù),如果發(fā)現(xiàn)某個(gè)線(xiàn)程(假設(shè)其為t1)在持有某個(gè)同步對(duì)象(假設(shè)其為s1),同時(shí)又在調(diào)用同步原語(yǔ)等待其它同步對(duì)象(假設(shè)其為s2)時(shí),即可得知第二個(gè)條件被滿(mǎn)足.在此基礎(chǔ)上,若發(fā)現(xiàn)s2 已經(jīng)被其它線(xiàn)程持有(假設(shè)其為t2),而t2 也在等待其它的同步對(duì)象時(shí),以此類(lèi)推,若最后發(fā)現(xiàn)tn 在等待s1,則形成了循環(huán)等待,滿(mǎn)足第四個(gè)條件.一旦發(fā)現(xiàn)上述第二個(gè)與第四個(gè)條件被滿(mǎn)足,插件即可判定形成了死鎖.
在Qt Creator 菜單中增加“concurrency analyze”菜單,并添加“start”、“stop”和“detect deadlock”子菜單,在數(shù)據(jù)輸出面板中增加概覽視圖、時(shí)間線(xiàn)視圖和死鎖檢測(cè)視圖.
1)在概覽視圖中,顯示每個(gè)線(xiàn)程的生命周期、阻塞時(shí)間以及阻塞時(shí)間占比,在時(shí)間軸上顯示每個(gè)線(xiàn)程等待和占用共享資源的情況,從資源角度顯示每一個(gè)等待和占用該資源的線(xiàn)程.在性能數(shù)據(jù)窗口能實(shí)時(shí)顯示多線(xiàn)程上下文切換和資源爭(zhēng)用等數(shù)據(jù).
2)在時(shí)間線(xiàn)視圖中,按時(shí)間順序顯示每個(gè)并發(fā)事件的詳細(xì)信息,通過(guò)每個(gè)事件可以查看詳細(xì)函數(shù)調(diào)用棧.
3)在死鎖檢測(cè)視圖中,死鎖檢測(cè)報(bào)告能顯示所有線(xiàn)程循環(huán)等待信息,通過(guò)每條等待信息可以查看詳細(xì)函數(shù)調(diào)用棧.
本文在國(guó)產(chǎn)龍芯和申威平臺(tái)上實(shí)現(xiàn)了上述并發(fā)性能分析方案,其中龍芯運(yùn)行環(huán)境配置如表2所示,申威運(yùn)行環(huán)境配置如表3所示.
表2 龍芯運(yùn)行環(huán)境配置
表3 申威運(yùn)行環(huán)境配置
面向國(guó)產(chǎn)平臺(tái)的并發(fā)性能分析插件如圖5到圖7所示.在圖5中用戶(hù)打開(kāi)待分析工程,點(diǎn)擊圖中A 區(qū)“concurrency analyze”的“start”菜單,即可開(kāi)始采集性能數(shù)據(jù).點(diǎn)擊“stop”后進(jìn)入概覽視圖.在概覽視圖(圖5中B 區(qū))中能查看并發(fā)性能數(shù)據(jù),包括線(xiàn)程、并發(fā)資源、上下文切換等數(shù)據(jù).通過(guò)概覽視圖可以輔助用戶(hù)初步定位程序并發(fā)性能瓶頸.
圖5 插件概覽視圖
圖6 插件時(shí)間線(xiàn)視圖
圖7 插件死鎖檢測(cè)視圖
通過(guò)標(biāo)簽切換到時(shí)間線(xiàn)視圖,如圖6所示.在圖6中B 區(qū)按時(shí)間順序詳細(xì)顯示并發(fā)事件類(lèi)型、調(diào)用者和所屬線(xiàn)程,任意點(diǎn)擊并發(fā)數(shù)據(jù),在圖6中A 區(qū)顯示詳細(xì)的函數(shù)調(diào)用棧信息.通過(guò)時(shí)間線(xiàn)視圖可以詳細(xì)定位并發(fā)性能低效的位置.
打開(kāi)死鎖測(cè)試用例,點(diǎn)擊“detect deadlock”即可進(jìn)入死鎖檢測(cè)視圖,如圖7所示.在圖7中C 區(qū)給出死鎖檢測(cè)報(bào)告,如果程序存在死鎖,檢測(cè)報(bào)告會(huì)給出循環(huán)等待時(shí)每個(gè)線(xiàn)程等待的位置,任意點(diǎn)擊一處數(shù)據(jù),在圖7中B 區(qū)會(huì)顯示等待時(shí)刻的函數(shù)調(diào)用棧.通過(guò)死鎖檢測(cè)視圖可以精確定位死鎖位置.
本文闡述了Qt Creator 下的插件開(kāi)發(fā)機(jī)制,分析了目前國(guó)產(chǎn)平臺(tái)下多線(xiàn)程程序開(kāi)發(fā)遇到的瓶頸,設(shè)計(jì)了低開(kāi)銷(xiāo)的性能數(shù)據(jù)采集后端和人機(jī)友好的并發(fā)性能分析插件界面,實(shí)現(xiàn)了對(duì)Qt Creator 開(kāi)發(fā)工具的功能擴(kuò)展,大大提高國(guó)產(chǎn)平臺(tái)下多線(xiàn)程程序開(kāi)發(fā)效率,同時(shí)通過(guò)輔助優(yōu)化并發(fā)程序性能,有助于彌補(bǔ)當(dāng)前國(guó)產(chǎn)平臺(tái)性能較低的問(wèn)題.本文設(shè)計(jì)的插件進(jìn)一步豐富完善了國(guó)產(chǎn)平臺(tái)開(kāi)發(fā)生態(tài)鏈,對(duì)國(guó)產(chǎn)平臺(tái)進(jìn)一步推廣應(yīng)用起到一定促進(jìn)作用.
利用Qt Creator 的插件機(jī)制擴(kuò)展其并發(fā)性能分析功能可以有效輔助用戶(hù)開(kāi)發(fā)多線(xiàn)程程序,但仍然存在一些不足,如目前只能適用于國(guó)產(chǎn)龍芯和申威處理器平臺(tái),對(duì)于國(guó)產(chǎn)飛騰平臺(tái)還不支持,性能數(shù)據(jù)視圖設(shè)計(jì)比較簡(jiǎn)單,這些問(wèn)題需要在下一步工作中繼續(xù)改進(jìn).