
所以我有一個用 C++ 寫的程式。
它可以告訴我完成所有計算花了多長時間,並且它做了很多相當繁重的多線程計算。
我剛剛注意到,如果我在同一台機器上運行該程序,如果從 TTY 啟動,則需要大約 20-21 秒來完成所有計算,如果從 GNOME 終端啟動,則只需大約 0.2 秒。
是什麼原因造成的?它實際上是同一台機器上完全相同的檔案。
答案1
一些背景理論
CTRL好吧, ++和ALTGNOME Terminal後使用的內容F1都是同一概念的不同實作:模仿所謂的全螢幕終端機。
前者在Linux中稱為虛擬終端(VT),或通常簡稱為「控制台」。它使用一種特殊的「純文字」視訊模式,該模式仍然由 x86 相容平台(即「IBM PC」傳統平台)上的硬體視訊卡提供。後者是一個 GUI 應用程式。
兩者都為在其幫助下運行的應用程式提供了一組此類應用程式期望從“終端設備”獲得的設施(更多詳細資訊和進一步的指示 -這裡)。
眼前的問題
好的,現在讓我們轉向感知緩慢。
我確信你的問題的癥結在於你的程式執行了所謂的「阻塞」I/O。也就是說,每次你都會做類似的事情
std::cout << "Hello, world" << endl;
在您的程式碼中,首先連結到您的應用程式的 C++ 標準庫的程式碼啟動並處理發送到指定內容的內容的輸出溪流。
經過一定的處理(通常是一些緩衝)後,這些資料必須真正離開程式的運行過程,並實際輸出到程式將其輸出發送到的任何媒體。在 Linux(和其他 Unix 相容系統)上,這需要透過專用的呼叫內核系統調用(或者系統調用簡稱)命名write()
。
因此,C++ stdlib 最終會進行該write()
系統調用,然後等待它完成,也就是說,它等待內核回复「好的,資料接收者告訴它已獲取它」。
正如您可以推斷的那樣,您的程式輸出的資料的接收者是運行您的程式的終端(模擬器)——可以是 Linux VT,也可以是測試中的 GNOME 終端實例。 (整體情況更加複雜,因為核心不會將資料直接發送到正在運行的終端模擬器中,但我們不要使描述複雜化。)
因此,系統呼叫完成的速度write()
很大程度上取決於資料接收方處理它的速度!就您而言,GNOME Terminal 的速度更快。
我對差異的看法是,VT 驅動程式盡職盡責地渲染所有發送給它的數據,滾動它等,而GNOME 終端通過僅渲染它的尾部(無論適合終端的屏幕尺寸)來優化傳入數據的突發,並將其餘部分位於大多數 GUI 終端機模擬器所具有的所謂「滾動緩衝區」中。
要做的要點
重要的是,一旦您的程式執行任何 I/O 以及計算,並且您使用「掛鐘」計時器測量程式的計算速度,您通常可以很好地測量該 I/O 的速度O,而不是計算速度。
請注意,I/O 很棘手:您的進程可以是被搶佔(停止並將其資源移交給另一個進程)作業系統在任何時候要等待某些 I/O 資源可用於寫入(例如硬碟)。
因此,衡量「原始」計算效能的可靠方法是在程式中使用某種功能來停用所有 I/O。如果這是不可能的或太醜陋而無法實現,至少嘗試/dev/null
透過運行您的程式將所有輸出定向到所謂的“空設備”
$ ./program >/dev/null
空設備只是丟棄所有傳遞給它的資料。所以,是的,C++ stdlib 執行的每個 I/O 回合仍然會影響內核,但至少您將擁有幾乎恆定(並且幾乎是即時)的寫入速度。
如果您需要這兩種措施和產生的數據,考慮創建一個所謂的 RAM 磁碟並將輸出重定向到位於那裡的檔案。
關於測量的更多內容:請注意,即使在運行商用作業系統(例如 Ubuntu 或其他作業系統)的看似空閒的系統上,CPU 也不會休眠 - 總是有一些任務在後台執行操作。這意味著即使沒有任何 I/O 或使用某種“禁用”I/O(如上所述)測量計算性能仍然會在每次運行時產生不同的結果。
為了彌補這一點,良好的基準測試意味著使用相同的輸入資料運行計算數千次,並對運行次數的結果進行平均。