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