覃仁諒,寧芊,嚴(yán)華
(四川大學(xué)電子信息學(xué)院,成都 610065)
數(shù)據(jù)可視化作為數(shù)據(jù)分析的一種重要的技術(shù),能夠有效地提高工程的效率和準(zhǔn)確性,已經(jīng)被廣泛用于多個領(lǐng)域[1],特別是在一些復(fù)雜工業(yè)領(lǐng)域,工程上需要采用多窗體圖形顯示來同時對多個條件變量進行實時監(jiān)測。例如,在變電站綜合分析系統(tǒng)中,需要對電流、電壓、溫度等實時數(shù)據(jù)進行實時顯示和分析,以實現(xiàn)對數(shù)據(jù)采集設(shè)備和采集狀態(tài)的監(jiān)控[2];在地震前兆臺網(wǎng)監(jiān)控系統(tǒng)中,需要同時對多個前兆儀器的采集數(shù)據(jù)進行實時顯示,以便于儀器管理人員對儀器進行監(jiān)測和監(jiān)測預(yù)報人員對數(shù)據(jù)進行觀測[3];在情報雷達顯控系統(tǒng)中,需要對雷達P顯、B顯、E顯、A顯等多種二維顯示方式進行多窗體同時顯示,以便于雷達操作人員對雷達探測結(jié)果進行分析,從而使他們做出更加精準(zhǔn)的判斷和決策[4]。
數(shù)據(jù)采集技術(shù)的發(fā)展和工程應(yīng)用的需求,使得數(shù)據(jù)采樣頻率越來越快、數(shù)據(jù)規(guī)模也越來越大,單個圖形顯示窗體所需時間也越來越長,因此對多窗體圖形繪制的效率也提出了更高的要求。傳統(tǒng)方法在繪制多窗體圖形時,單個數(shù)據(jù)幀的數(shù)據(jù)圖形化總時間隨著數(shù)據(jù)圖形窗體數(shù)量增加而線性增加,從而導(dǎo)致數(shù)據(jù)圖形繪制效率與實時性降低,難以滿足高實時性的多窗體圖形顯示需求。
隨著CPU多核并行技術(shù)的發(fā)展,CPU多核并行計算已經(jīng)被廣泛用于多個領(lǐng)域[5]。通過在多個CPU核上進行負載分擔(dān)來提高系統(tǒng)的性能。由于多窗體圖形顯示數(shù)據(jù)的獨立性,即多個窗體圖形數(shù)據(jù)之間不具有相干性,因此針對傳統(tǒng)多窗體圖形繪制效率低的問題,結(jié)合雙緩沖繪圖技術(shù)[6],提出了基于Qt的多窗體快速并行圖形繪制方法。該方法利用CPU多核多線程并行計算能力實現(xiàn)對多窗體圖形的繪制,提高了多窗體圖形繪制的效率,大大減少了單個數(shù)據(jù)幀的數(shù)據(jù)可視化總時間。
Qt作為一種基于C++的跨平臺GUI(Graphical Us?er Interface)系統(tǒng),能夠給應(yīng)用程序開發(fā)者提供建立圖形用戶界面所需的所有功能。同時,Qt是純面向?qū)ο蟮?,由于其具有良好的封裝機制,模塊化程度非常高,有良好的可重用性,大大方便了用戶的開發(fā)。
Qt繪圖系統(tǒng)主要由三部分組成,分別為QPainter類、QPaintDevice類、QPaintEngine類。其中QPainter類用于執(zhí)行繪圖操作,相當(dāng)于畫家,提供drawPixmap、drawImage等各種繪圖命令,QPaintDevice類相當(dāng)于畫布,提供 QImage、QPixmap、QBitmap、QPicture等畫布類接口,QPaintEngine類提供了QPainter類用來繪制到不同類型設(shè)備的接口,是基本QPainter類繪圖命令的具體實現(xiàn)。Qt繪圖系統(tǒng)組成關(guān)系如圖1所示。
圖1 Qt繪圖系統(tǒng)組成關(guān)系
Qt線程主要由線程類和線程同步類組成,其中QThread是線程類接口,提供了一個與平臺無關(guān)的方法來管理線程,線程同步類包括QMutex、QSemphore、QWaitCondition、QReadWriteLock等,提供了線程同步接口。在Qt圖形用戶界面的應(yīng)用程序中,GUI線程是圖形用戶界面的主線程,是Qt中唯一可以執(zhí)行GUI相關(guān)操作的線程,但它可以同時擁有一個或者多個非GUI線程作為工作線程,以便于處理應(yīng)用程序中其他耗時操作。
信號與槽機制是Qt的核心機制,主要用于對象間的通信。它可以通過已有的信號和槽或自定義的信號和槽,將互不了解的對象綁定在一起。信號與槽的連接方式主要包括自動連接、直接連接、隊列連接、隊列阻塞連接等。一個信號和槽連接后,每當(dāng)一個對象發(fā)射該信號時,就會自動調(diào)用該槽函數(shù),特別是信號與槽機制可以支持跨線程的連接,處于不同線程的對象也可以使用信號與槽進行連接,從而可以實現(xiàn)線程間的通信。
在傳統(tǒng)的多窗體圖形顯示系統(tǒng)中,多窗體圖形顯示的數(shù)據(jù)由數(shù)據(jù)采集設(shè)備實時提供,并且通過串口或網(wǎng)絡(luò)等傳輸方式將采集的數(shù)據(jù)以數(shù)據(jù)幀的形式發(fā)送給顯控系統(tǒng)。顯控系統(tǒng)采用一個單獨工作線程來實時獲取數(shù)據(jù)幀,而每個數(shù)據(jù)幀都是一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)幀中封裝了多窗體圖形顯示所需要的數(shù)據(jù)。通過解析該數(shù)據(jù)幀獲得每個顯示窗體所需要的顯示數(shù)據(jù)。隨后多個窗體按照串行方式進行多窗體圖形繪制,即先完成當(dāng)前窗體圖形的數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖、輸出窗體圖形等操作后,再去執(zhí)行下一個窗體圖形繪制操作,最終完成多窗體圖形的繪制。算法實現(xiàn)的流程如圖2所示。
圖2 傳統(tǒng)的多窗體圖形繪制方法
圖形繪制采用雙緩沖繪圖技術(shù),其主要由內(nèi)存繪圖和圖形輸出兩部分組成。通過多圖層和貼圖的方法實現(xiàn)圖形繪制[7],不僅能夠解決圖形界面閃爍問題,而且也能夠加快圖形的繪制速度。
但傳統(tǒng)的多窗體圖形繪制方法僅采用一個界面主線程來串行完成多個窗體圖形的繪制。隨著數(shù)據(jù)的規(guī)模越來越大,繪圖任務(wù)越來越復(fù)雜,則單個窗體圖形繪制時間越長。此時在多窗體圖形顯示情況下,單個數(shù)據(jù)幀的數(shù)據(jù)圖形化總時間隨著繪圖窗體數(shù)量的增加而線性增加,嚴(yán)重影響到整個圖形顯示系統(tǒng)的效率,導(dǎo)致數(shù)據(jù)圖形的實時性降低,從而不能滿足系統(tǒng)的需求。因此,在傳統(tǒng)的多窗體圖形繪制的基礎(chǔ)上提出了基于Qt的多窗體快速并行圖形繪制方法。
數(shù)據(jù)采集的一次信息數(shù)據(jù)封裝在一個數(shù)據(jù)幀中,界面主線程通過解析該數(shù)據(jù)幀,將多個窗體圖形顯示數(shù)據(jù)分別存放在不同的緩沖區(qū),接著分別相互獨立的進行數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖、輸出圖形等操作,因此多窗體圖形顯示的數(shù)據(jù)之間沒有相干性,即一個窗體圖形顯示的數(shù)據(jù)不依賴于其他窗體圖形顯示的數(shù)據(jù)。
在具有圖形用戶界面的Qt應(yīng)用程序中,由于GUI相關(guān)操作只能在界面主線程中執(zhí)行,因此輸出圖形操作只能在界面主線程完成,而數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖等操作可以搬移到其他工作線程上執(zhí)行,特別是內(nèi)存繪圖操作。QImage和QPixmap作為Qt的畫布類接口,在功能上有著不同的地方。QImage是為I/O設(shè)計和優(yōu)化的,可用于直接像素訪問和操作,在QImage上使用QPainter畫家類時,內(nèi)存繪圖操作是可以在非GUI線程中執(zhí)行,而不需要在GUI線程中處理,從而可以很大幅度提高圖形界面的響應(yīng)速度;QPix?map在屏幕顯示圖像方面進行了相關(guān)的設(shè)計優(yōu)化,從而使得采用QPixmap進行輸出圖形具有更好的顯示效果。此外,GUI線程與非GUI線程可以通過Qt信號與槽機制實現(xiàn)線程間通信。
Linux操作系統(tǒng)中提供的LinuxThreads庫是內(nèi)核級方式,庫中的線程其實是一種輕權(quán)進程LWP[8]。Linux系統(tǒng)中,Qt線程的實現(xiàn)采用了LinuxThreads庫。在CPU多核處理器上,操作系統(tǒng)為了充分利用CPU多核資源,同一應(yīng)用程序中的多個線程任務(wù)將在操作系統(tǒng)的調(diào)度下分配到CPU的多個核上進行處理。通過CPU綁定技術(shù)[9],將多線程綁定在不同CPU核上,從而實現(xiàn)多線程任務(wù)真正的并行。
結(jié)合多窗體圖形顯示的數(shù)據(jù)特點、Qt繪圖引擎特點以及Linux多線程特點,當(dāng)數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖等任務(wù)耗時程度較大時,多窗體圖形繪制通過利用CPU多核多線程并行計算能力,實現(xiàn)多窗體圖形數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖的并行化計算,從而提高多窗體圖形繪制的效率。因此提出了一種基于Qt的多窗體快速并行圖形繪制方法。
(1)繪圖工作線程的并行化操作
每個窗體圖形繪制都對應(yīng)一個繪圖工作線程,利用CPU綁定技術(shù)讓繪圖工作線程分別運行在不同CPU核上。而每個繪圖工作線程主要完成數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖等并行化操作,同時與界面主線程進行線程間通信。算法實現(xiàn)的流程如圖3所示。
當(dāng)界面主線程解析數(shù)據(jù)幀后,則會向每個繪圖工作線程發(fā)送startPaint信號,繪圖工作線程接收到start?Paint信號后,開始進行獲取顯示數(shù)據(jù)、數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖等操作,當(dāng)完成這些操作后,繪圖工作線程向界面主線程發(fā)送finishPaint信號,通知界面主線程進行圖形輸出操作。即將耗時的內(nèi)存繪圖等操作放在繪圖工作線程上執(zhí)行,而界面主線程則只負責(zé)多個窗體的圖形輸出操作以及其他UI操作。
圖3 繪圖工作線程的并行化操作
(2)圖形的輸出
雙緩沖繪圖機制主要包括內(nèi)存繪圖和內(nèi)存拷貝到顯存操作,而圖形的輸出是屬于內(nèi)存拷貝到顯存操作。由于圖形顯示具有圖形縮放、圖形拖動等功能,因此內(nèi)存拷貝到顯存操作需要根據(jù)當(dāng)前窗體的顯示內(nèi)容來進行選擇性內(nèi)存拷貝,繪圖內(nèi)存與顯示窗體之間的映射如圖4所示。
圖4 繪圖內(nèi)存與顯示窗體之間的映射
具體實現(xiàn)方法為:假設(shè)當(dāng)前顯示窗體為(wX,xY,wWidth,wHeight),其中(wX,xY)表示當(dāng)前顯示窗體可見范圍的左頂點坐標(biāo),wWidth和wHeight分別表示當(dāng)前顯示窗體可見坐標(biāo)范圍的寬和高,當(dāng)前顯示窗體相對應(yīng)的需要拷貝的繪圖內(nèi)存塊為(mX,mY,mWidth,mHeight),其中(mX,mY)表示當(dāng)前拷貝繪圖內(nèi)存塊的左頂點坐標(biāo),mWidth和mHeight分別表示當(dāng)前需要拷貝的繪圖內(nèi)存塊的寬和高。
當(dāng)繪圖工作線程在QImage繪圖內(nèi)存上完成內(nèi)存繪圖工作后,界面主線程先通過繪圖內(nèi)存塊與顯示窗體之間的映射關(guān)系,即由當(dāng)前顯示窗體(wX,xY,wWidth,wHeight),通過映射公式計算出當(dāng)前需拷貝的繪圖內(nèi)存塊(mX,mY,mWidth,mHeight),接著通過調(diào)用 QImage的函數(shù)接口,將繪圖內(nèi)存塊(mX,mY,mWidth,mHeight)縮放至顯示窗體大小,隨后將QImage對象轉(zhuǎn)換成QPix?map對象,最后通過調(diào)用Qt繪圖引擎的API函數(shù),將QPixmap內(nèi)存塊拷貝至顯存進行圖形顯示,從而實現(xiàn)圖形的輸出。繪圖內(nèi)存塊與顯示窗體之間的映射公式如式(1)、式(2)、式(3)、式(4)所示。
其中,mWidth和mHeight分別表示QImage繪圖內(nèi)存的最大寬度、最大高度,wXLower和wXUpper分別表示顯示窗體橫軸X最小值、最大值,wYLower和wYUpper分別表示顯示窗體縱軸Y的最小值、最大值,wScale表示當(dāng)前圖形縮放比例。
(3)多窗體快速并行圖形繪制的實現(xiàn)
根據(jù)多窗體快速并行圖形繪制的思想,在多線程進行CPU綁定后,若獲取的數(shù)據(jù)幀為DataFrame,窗體數(shù)量為FormCount,解析數(shù)據(jù)幀得到的顯示數(shù)據(jù)為Raw?Data[FormCount][DataSize],經(jīng)數(shù)據(jù)處理后為Daat[Data?Size],數(shù)據(jù)坐標(biāo)映射后為MapData[DataSize]。實現(xiàn)的偽代碼如下:
1.Begin
2.getDataFrame(DataFrame)
3.parseDataFrame(DataFrame,RowData)
4.loop i from 0 to FormCount-1 in parallel processing
5.Data=dataProcess(RowData[i,DataSize])
6. loop j from 0 to DataSize-1 in step of 1
7. MapData[j]=map(Data[j])
8. end of loop
9.drawImage(MapData)
10.end of loop
11.outputGraphics()
12.End
其中,getDataFrame用于獲取數(shù)據(jù)幀,parse?DataFrame函數(shù)用于解析數(shù)據(jù)幀獲得多窗體圖形顯示的數(shù)據(jù),dataProcess函數(shù)用于對數(shù)據(jù)進行處理,map函數(shù)用于對處理后的數(shù)據(jù)進行坐標(biāo)映射,drawQImage函數(shù)用于根據(jù)得到的MapData數(shù)據(jù)進行內(nèi)存繪圖操作,outputGraphics函數(shù)用于將內(nèi)存塊拷貝至顯存,以實現(xiàn)圖形輸出。
分析上述偽代碼可知,每個顯示窗體的數(shù)據(jù)相互獨立,因此可以將多個顯示窗體的耗時操作由不同的工作線程并行處理計算,而界面主線程只負責(zé)多個圖形的輸出操作以及其他UI操作,這樣不僅可以提高多窗體圖形繪制的效率,而且很大程度上提高了圖形界面的響應(yīng)速度。
根據(jù)上述的分析,多窗體快速并行圖形繪制算法主要由以下4個步驟實現(xiàn)。
(1)數(shù)據(jù)幀的獲?。簽榱双@取實時的數(shù)據(jù)幀,同時也為了提高圖形界面的響應(yīng)速度,數(shù)據(jù)幀的獲取操作由單獨的工作線程來執(zhí)行。
(2)數(shù)據(jù)幀的解析:為了適應(yīng)多窗體圖形的并行化操作,解析得到的多個窗體顯示數(shù)據(jù)將分別存放在不同緩沖區(qū)。
(3)多個窗體圖形繪制的并行化:不同窗體圖形顯示的數(shù)據(jù)處理、數(shù)據(jù)坐標(biāo)映射、內(nèi)存繪圖等操作,將由不同的繪圖工作線程來執(zhí)行。
(4)圖形的輸出:繪圖工作線程與界面主線程之間采用隊列阻塞式的信號與槽機制,即先完成內(nèi)存繪圖的顯示窗體將由界面主線程先執(zhí)行圖形的輸出操作,直到完成所有窗體圖形的顯示。
基于Qt的多窗體快速并行圖形繪制方法的實現(xiàn)流程如圖5所示。
圖5 基于Qt的快速并行圖形繪制方法實現(xiàn)流程
本文仿真在Linux、Intel Core八核i7-67003.4GHz、16GB內(nèi)存、Intel HD Graphics 530下進行。繪圖引擎為Qt5.6.1,編程環(huán)境為 Qt Creator 4.0.1,編程語言為C++。為了便于對兩種多窗體圖形的繪制方法進行比較,多窗體圖形以直角坐標(biāo)系上繪制二維曲線圖形為例。
繪制效率的對比以繪制時間和相對加速比作為比較標(biāo)準(zhǔn),其中繪制時間為單個數(shù)據(jù)幀的圖形化總時間,而相對加速比為單個數(shù)據(jù)幀的傳統(tǒng)方法繪制時間與快速并行方法繪制時間的比值。使用兩種繪制方法分別測試了不同繪制數(shù)據(jù)個數(shù)下的多窗體圖形繪制時間。
繪制數(shù)據(jù)個數(shù)為2000時,多窗體圖形繪制時間的對比如表1和圖6所示。繪制數(shù)據(jù)個數(shù)為4000時,多窗體圖形繪制時間的對如表2和圖7所示。繪制數(shù)據(jù)個數(shù)為8000時,多窗體圖形繪制時間的對比如表3和圖8所示。圖9表示不同繪制數(shù)據(jù)個數(shù)下,相對加速比與顯示窗體個數(shù)之間關(guān)系的對比。
表1 兩種方法的繪制效率比較(數(shù)據(jù)個數(shù):2000)
表2 兩種方法的繪制效率比較(數(shù)據(jù)個數(shù):4000)
表3 兩種方法的繪制效率比較(數(shù)據(jù)個數(shù):8000)
針對相同數(shù)據(jù)個數(shù)下的不同數(shù)量顯示窗體,對比傳統(tǒng)多窗體圖形繪制方法和快速并行多窗體圖形繪制方法的繪制時間可以看出:隨著顯示窗體數(shù)量的增加,快速并行的多窗體圖形繪制時間明顯小于傳統(tǒng)多窗體圖形的繪制時間。這是由于快速并行繪制方法將多窗體圖形的內(nèi)存繪圖等耗時操作交給繪圖線程,而繪圖線程綁定在不同CPU核上,從而提高了多窗體圖形的繪制效率。
針對相同數(shù)據(jù)個數(shù)下的不同數(shù)量顯示窗體,對比相對加速比可以看出:隨著顯示窗體數(shù)量的增加,快速并行繪制方法的相對加速比不斷增加,但增加的速率逐漸變慢。這是由于隨著顯示窗體數(shù)量的增加,界面主線程的圖形輸出隊列逐漸增長,導(dǎo)致并行繪制效率提升緩慢,因此基于Qt的多窗體快速并行圖形繪制方法中的圖形輸出操作應(yīng)具有較低的耗時程度。
圖6 繪制時間對比直方圖(數(shù)據(jù)個數(shù)為2000)
圖7 繪制時間對比直方圖 (數(shù)據(jù)個數(shù)為4000)
圖8 繪制時間對比直方圖 (數(shù)據(jù)個數(shù)為8000)
圖9 相對加速比曲線圖
在圖9中,針對不同數(shù)據(jù)個數(shù)下的相同數(shù)量顯示窗體,對比相對加速比可以看出:單個窗體圖形繪制數(shù)據(jù)個數(shù)越大,則快速并行繪制方法的相對加速比越大。這是由于單個窗體圖形繪制數(shù)據(jù)個數(shù)越大,則可并行任務(wù)的耗時程度越大,此時可以獲得更好的并行繪制效率。
系統(tǒng)資源利用率的對比以CPU核使用數(shù)為比較標(biāo)準(zhǔn)。在Linux系統(tǒng)中,通過top命令查看圖形界面應(yīng)用程序使用CPU核的數(shù)量,兩種多窗體圖形繪制方法的CPU核使用數(shù)量如表4所示。
表4 兩種繪制方法的CPU核使用數(shù)比較
從表4可看出,在窗體個數(shù)為6時,快速并行繪制方法的CPU核使用數(shù)是傳統(tǒng)繪制方法的4倍。這是由于傳統(tǒng)繪制方法只有2個線程,即獲取數(shù)據(jù)幀線程和界面主線程,這2個線程會在操作系統(tǒng)的調(diào)度下隨機運行在2個CPU核上,而快速并行繪制方法除了以上2個線程外,還有6個繪圖線程,這8個線程分別綁定在不同CPU核上。因此,在繪制多窗體圖形時,本文提出的方法的CPU核利用率明顯高于傳統(tǒng)多窗體圖形繪制方法,大大提高了系統(tǒng)資源利用率。
本文結(jié)合多窗體圖形顯示的數(shù)據(jù)特點、Qt繪圖引擎的特點以及Linux多線程的特點,在雙緩沖繪圖的基礎(chǔ)上,利用CPU多核多線程的并行計算能力,提出了基于Qt的多窗體快速并行圖形繪制方法。實驗表明,基于本文方法的多窗體圖形的繪制,有效地減少了單個數(shù)據(jù)幀的數(shù)據(jù)圖形化總時間,大大提高了多窗體圖形的繪制效率,同時也提高了系統(tǒng)資源的利用率。目前該方法已經(jīng)成功應(yīng)用于某雷達顯控系統(tǒng),并取得了良好的效果。