單核性能編譯
⑴ lammps 可以同時編譯 並行 和 單核嗎
並行技術可分為三類,分別是線程庫、消息傳遞庫和編譯器支持。線程庫(如 POSIX* 線程和 Windows* API 線程)可實現對線程的顯性控制;如果需要對線程進行精細管理,可以考慮使用這些顯性線程技術。藉助消息傳遞庫(如消息傳遞介面〔MPI〕),應用程序可同時利用多台計算機,它們彼此間不必共享同一內存空間。MPI 廣泛應用於科學計算領域。第三項技術是在編譯器中實現的線程處理支持,採用的形式自動並行化。一旦將線程處理引入到應用程序中,開發人員就可能要面對一系列新的編程缺陷(Bug)。其中許多缺陷是難以檢測到的,需要付出額外的時間和關注以確保程序的正確運行。一些比較常見的線程處理問題包括:數據爭用 ,同步,線程停頓 ,鎖 ,共享錯誤.
並行技術可以分為多進程編程和多線程編程。人們總會用某種IPC(inter-process communication,進程間通信)的形式來實現進程間同步,如管道(pipes),信號量(semaphores),信息隊列(message queues),或者共享存儲(shared memory)。在所有的這些IPC形式中,共享存儲器是最快的(除了門(doors)之外)。在處理進程間資源管理,IPC和同步時,你可以選擇 POSIX或者System V的定義。
線程技術早在20世紀60年代就被提出,但真正應用多線程到操作系統中還是在20世紀80年代中期。現在,多線程技術已經被許多操作系統所支持,包括Windows NT/2000和Linux。
在1999年1月發布的Linux 2.2內核中,進程是通過系統調用fork創建的,新的進程是原來進程的子進程。需要說明的是,在Linux 2.2.x中,不存在真正意義上的線程,Linux中常用的線程Pthread實際上是通過進程來模擬的。
也就是說,Linux中的線程也是通過fork創建的,是「輕」進程。Linux 2.2預設只允許4096個進程/線程同時運行,而高端系統同時要服務上千的用戶,所以這顯然是一個問題。它一度是阻礙Linux進入企業級市場的一大因素。
2001年1月發布的Linux 2.4內核消除了這個限制,並且允許在系統運行中動態調整進程數上限。因此,進程數現在只受制於物理內存的多少。在高端伺服器上,即使只安裝了512MB內存,現在也能輕而易舉地同時支持1.6萬個進程。
在Linux 2.5內核中,已經做了很多改進線程性能的工作。在Linux 2.6中改進的線程模型仍然是由Ingo Molnar 來完成的。它基於一個1:1的線程模型(一個內核線程對應一個用戶線程),包括內核內在的對新NPTL(Native Posix Threading Library)的支持,這個新的NPTL是由Molnar和Ulrich Drepper合作開發的。
2003年12月發布的Linux 2.6內核,對進程調度經過重新編寫,去掉了以前版本中效率不高的演算法。進程標識號(PID)的數目也從3.2萬升到10億。內核內部的大改變之一就是Linux的線程框架被重寫,以使NPTL可以運行其上。
在現代操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制來同步各執行單元對共享數據的訪問。尤其是在多處理器系統上,更需要一些同步機制來同步不同處理器上的執行單元對共享的數據的訪問。在主流的Linux內核中包含了幾乎所有現代的操作系統具有的同步機制,這些同步機制包括:原子操作、信號量(semaphore)、讀寫信號量(rw_semaphore)、spinlock、BKL(Big Kernel Lock)、rwlock、brlock(只包含在2.4內核中)、RCU(只包含在2.6內核中)和seqlock(只包含在2.6內核中)。
現在的隨著現在計算機體系結構的發展,指令級的並行和線程級的並行都在日新月異地發展著.
⑵ 多核編程與單核編程的區別
多核對於單核的好處是可以真正地同時處理多件事情,因此如果程序想要在多核CPU上獲得更好的性能的話,使用多線程技術是必需的。但是採用多線程涉及到線程間數據同步的問題,程序員必須在線程間協調好對數據的訪問和處理。
不過我覺得多核編程與單核編程的區別並不是指線程同步問題,因為單核編程同樣可以使用多線程,同樣需要面對線程同步的問題。同樣的代碼不經過特別優化,均可以在多核CPU和單核CPU上運行得很好,只不過運行效率不同罷了。
所以我覺得多核編程和單核編程的區別在於對多線程技術需求的迫切程度。如果程序針對多核環境來編程,那麼必然要採用多線程技術,以獲得更好的性能;如果程序只針對單核環境,那麼對多線程並不是那麼敏感,但如果它採用了多線程,一旦在多核環境運行,它也能獲得性能的提升。
⑶ 單核cpu的並行過程,求解答
CPU並行編程概述
並行編程的演化
一個自然而然的問題是:為什麼要用並行編程?在20世紀70年代、80年代甚至90年代的一部分時間里,我們對單線程編程(或者稱為串列編程)非常滿意。你可以編寫一個程序來完成一項任務。執行結束後,它會給你一個結果。任務完成,每個人都會很開心!雖然任務已經完成,但是如果你正在做一個每秒需要數百萬甚至數十億次計算的粒子模擬,或者正在對具有成千上萬像素的圖像進行處理,你會希望程序運行得更快一些,這意味著你需要更快的CPU。
在2004年以前,CPU製造商IBM、英特爾和AMD都可以為你提供越來越快的處理器,處理器時鍾頻率從16 MHz、20 MHz、66 MHz、100 MHz,逐漸提高到200 MHz、333 MHz、466 MHz⋯⋯看起來它們可以不斷地提高CPU的速度,也就是可以不斷地提高CPU的性能。但到2004年時,由於技術限制,CPU速度的提高不能持續下去的趨勢已經很明顯了。這就需要其他技術來繼續提供更高的性能。CPU製造商的解決方案是將兩個CPU放在一個CPU內,即使這兩個CPU的工作速度都低於單個CPU。例如,與工作在300 MHz速度上的單核CPU相比,以200 MHz速度工作的兩個CPU(製造商稱它們為核心)加在一起每秒可以執行更多的計算(也就是說,直觀上看2×200 > 300)。
聽上去像夢一樣的「單CPU多核心」的故事變成了現實,這意味著程序員現在必須學習並行編程方法來利用這兩個核心。如果一個CPU可以同時執行兩個程序,那麼程序員必須編寫這兩個程序。但是,這可以轉化為兩倍的程序運行速度嗎?如果不能,那我們的2×200 > 300的想法是有問題的。如果一個核心沒有足夠的工作會怎麼樣?也就是說,只有一個核心是真正忙碌的,而另一個核心卻什麼都不做?這樣的話,還不如用一個300 MHz的單核。引入多核後,許多類似的問題就非常突出了,只有通過編程才能高效地利用這些核心。
核心越多,並行性越高
程序員不能簡單地忽略CPU製造商每年推出的更多數量的核心。2015年,英特爾在市場上推出8核台式機處理器i7-5960X[11]和10核工作站處理器,如Xeon E7-8870 [14]。很明顯,這種多核狂熱在可預見的未來會持續下去。並行編程從2000年年初的一種奇異的編程模型轉變為2015年唯一被接受的編程模型。這種現象並不局限於台式電腦。在移動處理器方面,iPhone和Android手機都有2個或4個核。預計未來幾年,移動領域的核心數量將不斷增加。
那麼,什麼是線程?要回答這個問題,讓我們來看看8核INTEL CPU i7-5960X [11]。 INTEL的文檔說這是一個8C/16T CPU。換句話說,它有8個核心,但可以執行16個線程。你也許聽到過並行編程被錯誤地稱為多核編程。正確的術語應該是多線程編程。這是因為當CPU製造商開始設計多核架構時,他們很快意識到通過共享一些核心資源(如高速緩存)來實現在一個核心中同時執行兩項任務並不困難。
類比1.1:核心與線程
圖1-1顯示了兩個兄弟Fred和Jim,他們是擁有兩台拖拉機的農民。每天,他們開車從農舍到椰子樹所在的地方,收獲椰子並把它們帶回農舍。他們用拖拉機內的錘子來收獲(處理)椰子。整個收獲過程由兩個獨立但有序的任務組成,每個任務需要30秒:任務1是從拖拉機走向椰子樹,每次帶回1顆椰子。任務2是用錘子敲碎(處理)它們,並將它們存放在拖拉機內。Fred每分鍾可以處理1顆椰子,而Jim每分鍾也可以處理1顆椰子。綜合起來,他們倆每分鍾可以處理2顆椰子。
一天,Fred的拖拉機發生了故障。他把拖拉機留在修理廠,並把椰子錘忘在了拖拉機內。回到農舍的時候已經太遲了,但他們仍然有工作要做。只使用Jim的拖拉機和裡面的1把椰子錘,他們還能每分鍾處理2顆椰子嗎?
核心與線程
讓我們來看看圖1-1中描述的類比1.1。如果收獲1顆椰子需要完成兩個連續的任務(我們將它們稱為線程):線程1從樹上摘取1顆椰子並花費30秒將它帶回拖拉機,線程2花費30秒用拖拉機內的錘子敲碎(處理)該椰子,這樣可以在60秒內收獲1顆椰子(每分鍾1顆椰子)。如果Jim和Fred各自都有自己的拖拉機,他們可以簡單地收獲兩倍多的椰子(每分鍾2顆椰子),因為在收獲每顆椰子時,他們可以共享從拖拉機到椰子樹的道路,並且他們各自擁有自己的錘子。
在這個類比中,一台拖拉機就是一個核心,收獲一顆椰子就是針對一個數據單元的程序執行。椰子是數據單元,每個人(Jim、Fred)是一個執行線程,需要使用椰子錘。椰子錘是執行單元,就像核心中的ALU一樣。該程序由兩個互相依賴的線程組成:在線程1執行結束之前,你無法執行線程2。收獲的椰子數量意味著程序性能。性能越高,Jim和Fred銷售椰子掙的錢就越多。可以將椰子樹看作內存,你可以從中獲得一個數據單元(椰子),這樣在線程1中摘取一顆椰子的過程就類似於從內存中讀取數據單元。
並行化更多的是線程還是核心
現在,讓我們看看如果Fred的拖拉機發生故障後會發生什麼。過去他們每分鍾都能收獲兩顆椰子,但現在他們只有一台拖拉機和一把椰子錘。他們把拖拉機開到椰子樹附近,並停在那兒。他們必須依次地執行線程1(Th1)和線程2(Th2)來收獲1顆椰子。他們都離開拖拉機,並在30秒內走到椰子樹那兒,從而完成了Th1。他們帶回挑好的椰子,現在,他們必須敲碎椰子。但因為只有1把椰子錘,他們不能同時執行Th2。Fred不得不等Jim先敲碎他的椰子,並且在Jim敲碎後,他才開始敲。這需要另外的30+30秒,最終他們在90秒內收獲2顆椰子。雖然效率不如每分鍾2顆椰子,但他們的性能仍然從每分鍾1顆提升至每分鍾1.5顆椰子。
收獲一些椰子後,Jim問了自己一個問題:「為什麼我要等Fred敲碎椰子?當他敲椰子時,我可以立即走向椰子樹,並摘獲下1顆椰子,因為Th1和Th2需要的時間完全相同,我們肯定不會遇到需要等待椰子錘空閑的狀態。在Fred摘取1顆椰子回來的時候,我會敲碎我的椰子,這樣我們倆都可以是100%的忙碌。」這個天才的想法讓他們重新回到每分鍾2顆椰子的速度,甚至不需要額外的拖拉機。重要的是,Jim重新設計了程序,也就是線程執行的順序,讓所有的線程永遠都不會陷入等待核心內部共享資源(比如拖拉機內的椰子錘)的狀態。正如我們將很快看到的,核心內部的共享資源包括ALU、FPU、高速緩存等,現在,不要擔心這些。
我在這個類比中描述了兩個配置場景,一個是2個核心(2C),每個核心可以執行一個單線程(1T);另一個是能夠執行2個線程(2T)的單個核心(1C)。在CPU領域將兩種配置稱為2C/2T與lC/2T。換句話說,有兩種方法可以讓一個程序同時執行2個線程:2C/2T(2個核心,每個核心都可以執行1個線程—就像Jim和Fred的兩台單獨的拖拉機一樣)或者lC/2T(單個核心,能夠執行2個線程—就像Jim和Fred共享的單台拖拉機一樣)。盡管從程序員的角度來看,它們都意味著具有執行2個線程的能力,但從硬體的角度來看,它們是非常不同的,這要求程序員充分意識到需要共享資源的線程的含義。否則,線程數量的性能優勢可能會消失。再次提醒一下:全能的INTEL i7-5960X [11] CPU是8C/l6T,它有8個核心,每個核心能夠執行2個線程。
圖1-2顯示了三種情況:a)是具有2個獨立核心的2C/2T情況;b)是具有糟糕編程的1C/2T情況,每分鍾只能收獲1.5顆椰子;c)是對椰子錘的需求永遠不會同時發生的順序正確版本,每分鍾可以收獲2顆椰子。
核心資源共享的影響
Jim為自己的發現感到自豪,他們的速度提高到每分鍾2顆椰子,Jim希望繼續創造一些方法來用一台拖拉機完成更多的工作。一天,他對Fred說:「我買了一把新的自動椰子錘,它在10秒內就能敲碎1顆椰子。」他們對這一發現非常滿意,立即出發並將拖拉機停在椰子樹旁。這次他們知道在開始收獲前必須先做好計劃⋯⋯
Fred問道:「如果我們的Th1需要30秒,而Th2需要10秒,並且我們唯一需要共享資源的任務是Th2(椰子錘),我們應該如何收獲椰子?」答案對他們來說很清楚:唯一重要的是線程的執行順序(即程序的設計),應確保他們永遠不會遇到兩人同時執行Th2並需要唯一的椰子錘(即共享核心資源)的情況。換句話說,它們的程序由兩個互相依賴的線程組成:Th1需要30秒,並且不需要共享(內存)資源,因為兩個人可以同時步行到椰子樹。Th2需要10秒並且不能同時執行,因為他們需要共享(核心)資源:椰子錘。由於每顆椰子需要30+10=40秒的總執行時間,他們能夠期望的最好結果是40秒收獲2顆椰子,如
圖1-2 d所示。如果每個人都按順序執行Th1和Th2,且不等待任何共享資源,則會發生這種情況。所以,他們的平均速度將是每分鍾3顆椰子(即每顆椰子平均20秒)。
內存資源共享的影響
用新的椰子錘實現了每分鍾收獲3顆椰子後,Jim和Fred第二天開始工作時看到了可怕的一幕。因為昨晚的一場大雨阻塞了半邊道路,從拖拉機到椰子樹的道路今天只能由一個人通行。所以,他們再次制訂計劃⋯⋯現在,他們有2個線程,每個線程都需要一個不能共享的資源。Th1(30秒—表示為30s)只能由一人執行,而Th2(10s)也只能由一人執行。怎麼辦?
考慮多種選擇後,他們意識到其速度的限制因素是Th1,他們能達到的最好目標是30秒收獲1顆椰子。當可以同時執行Th1(共享內存訪問)時,每個人可以順序地執行10+30s,並且兩個人都可以持續運行而無須訪問共享資源。但是現在沒有辦法對這些線程進行排序。他們能夠期望的最好結果是執行10+30s並等待20s,因為在此期間兩人都需要訪問內存。他們的速度回到平均每分鍾2顆椰子,如圖1-2 e所示。
這場大雨使他們的速度降低到每分鍾2顆椰子。Th2不再重要,因為一個人可以不慌不忙地敲椰子,而另一個人正在去摘取椰子的路上。Fred提出了這樣一個想法:他們應該從農舍再拿一把(較慢)椰子錘來幫忙。然而,這對於此時的情況絕對沒有幫助,因為收獲速度的限制因素是Th1。這種來自於某個資源的限制因素被稱為資源競爭。這個例子展示了當訪問內存是我們程序執行速度的限制因素時會發生什麼。處理數據的速度有多快(即核心運行速度)已無關緊要。我們將受到數據獲取速度的限制。即使Fred有一把可以在1秒鍾內敲碎椰子的椰子錘,但如果存在內存訪問競爭,他們仍然會被限制為每分鍾2顆椰子。在本書中,我們將區分兩種不同類型的程序:核心密集型,該類型不大依賴於內存訪問速度;存儲密集型,該類型對內存訪問速度高度敏感,正如我剛才提到的那樣。
第一個串列程序
我們已經理解了椰子世界中的並行編程,現在是時候將這些知識應用於真實計算機編程了。我會先介紹一個串列(即單線程)程序,然後將其並行化。我們的第一個串列程序imf?lip.c讀入圖1-3(左)中的小狗圖片並將其水平(中)或垂直(右)翻轉。為了簡化程序的解釋,我們將使用Bitmap(BMP)圖像格式,並將結果也輸出為BMP格式。這是一種非常容易理解的圖像格式,可以讓我們專注於程序本身。不要擔心本章中的細節,它們很快就會被解釋清楚,目前可以只關注高層的功能。
imflip.c源文件可以在Unix提示符下編譯和執行,如下所示:
gcc imflip.c -o imflip
./imflip dogL.bmp dogh.bmp V
在命令行中用「H」指定水平翻轉圖像(圖1-3中),用「V」指定垂直翻轉(圖1-3右側)。你將看到如下所示的輸出(數字可能不同,取決於你電腦的速度):
Input BMP File name : dogL.bmp (3200×2400)
Output BMP File name : dogh.bmp (3200×2400)
Total execution time : 81.0233 ms (10.550 ns per pixel)
運行該程序的CPU速度非常快,以致我必須將原始的640×480的圖像dog.bmp擴展為3200×2400的dogL.bmp,這樣它的運行時間才能被測量出來;dogL.bmp的每個維度擴大到原來的5倍,因此比dog.bmp大25倍。統計時間時,我們必須在圖像翻轉開始和結束時記錄CPU的時鍾。
理解數據傳輸速度
從磁碟讀取圖像的過程(無論是SSD還是硬碟驅動器)應該從執行時間中扣除,這很重要。換句話說,我們從磁碟讀取圖像,並確保它位於內存中(在我們的數組中),然後只統計翻轉操作所需的時間。由於不同硬體部件的數據傳輸速度存在巨大差異,我們需要分別分析在磁碟、內存和CPU上花費的時間。
在本書將要編寫的眾多並行程序中,我們重點關注CPU執行時間和內存訪問時間,因為我們可以控制它們。磁碟訪問時間(稱為I/O時間)通常在單線程中就達到極限,因而幾乎看不到多線程編程的好處。另外,請記住,當我們開始GPU編程時,較慢的I/O速度會嚴重困擾我們,因為I/O是計算機中速度最慢的部分,並且從CPU到GPU的數據傳輸要通過I/O子系統的PCI express匯流排進行,因此我們將面臨如何將數據更快地提供給GPU的挑戰。沒有人說GPU編程很容易!為了讓你了解不同硬體部件的傳輸速度,我在下面列舉了一些:
典型的網卡(NIC)具有1 Gbps的傳輸速度(千兆比特每秒或一億比特每秒)。這些卡俗稱「千兆網卡」或「Gig網卡」。請注意,1 Gbps只是「原始數據」的數量,其中包括大量的校驗碼和其他同步信號。傳輸的實際數據量少於此數量的一半。我的目的是給讀者一個大致的概念,這個細節對我們來說並不重要。
即使連接到具有6 Gbps峰值傳輸速度的SATA3介面,典型的硬碟驅動器(HDD)也幾乎無法達到1 Gbps〜2 Gbps的傳輸速度。HDD的機械讀寫性質根本不能實現快速的數據訪問。傳輸速度甚至不是硬碟的最大問題,最大問題是定位時間。HDD的機械磁頭需要一段時間在旋轉的金屬柱面上定位需要的數據,這迫使它在磁頭到達數據所在位置前必須等待。如果數據以不規則的方式分布(即碎片式的存放),則可能需要毫秒(ms)級的時間。因此,HDD的傳輸速度可能遠遠低於它所連接的SATA3匯流排的峰值速度。
連接到USB 2.0埠的快閃記憶體磁碟的峰值傳輸速度為480 Mbps(兆比特每秒或百萬比特每秒)。但是,USB 3.0標准具有更快的5 Gbps傳輸速度。更新的USB 3.1可以達到10 Gbps左右的傳輸速率。由於快閃記憶體磁碟使用快閃記憶體構建,它不需要查找時間,只需提供地址即可直接訪問數據。
典型的固態硬碟(SSD)可以連接在SATA3介面上,達到接近4 Gbps〜5 Gbps的讀取速度。因此,實際上SSD是唯一可以達到SATA3介面峰值速度的設備,即以預期的6 Gbps峰值速率傳輸數據。
一旦數據從I/O(SDD、HDD或快閃記憶體磁碟)傳輸到CPU的內存中,傳輸速度就會大大提高。已發展到第6代的Core i7系列(i7-6xxx),更高端的Xeon CPU使用DDR2、DDR3和DDR4內存技術,內存到CPU的傳輸速度為20 GBps〜60 GBps(千兆位元組每秒)。注意這個速度是千兆位元組。一個位元組有8個比特,為與其他較慢的設備進行比較,轉換為存儲訪問速度時為160 Gbps〜480 Gbps(千兆比特每秒)。
正如我們將在第二部分及以後所看到的,GPU內部存儲器子系統的傳輸速度可以達到100 GBps〜1000 GBps。例如,新的Pascal系列GPU就具有接近後者的內部存儲傳輸速率。轉換後為8000 Gbps,比CPU內部存儲器快一個數量級,比快閃記憶體磁碟快3個數量級,比HDD快近4個數量級。
imflip.c中的main( )函數
代碼1.1中所示的程序會讀取一些命令行參數,並按照命令行參數垂直或水平地翻轉輸入圖像。命令行參數由C放入argv數組中。
clock( )函數以毫秒為單位統計時間。重復執行奇數次(例如129次)操作可以提高時間統計的准確性,操作重復次數在"#define REPS 129"行中指定。該數字可以根據你的系統更改。
ReadBMP( )函數從磁碟讀取源圖像,WriteBMP( )將處理後的(即翻轉的)圖像寫回磁碟。從磁碟讀取圖像和將圖像寫入磁碟的時間定義為I/O時間,我們從處理時間中去除它們。這就是為什麼我在實際的圖像翻轉代碼之間添加"start = clock( )"和"stop = c1ock( )"行,這些代碼對已在內存中的圖像進行翻轉操作,因此有意地排除了I/O時間。
在輸出所用時間之前,imf?lip.c程序會使用一些free( )函數釋放所有由ReadBMP( )分配的內存以避免內存泄漏。
代碼1.1:imflip.c的main( ){⋯}
imflip.c中的main( )函數讀取3個命令行參數,用以確定輸入和輸出的BMP圖像文件名以及翻轉方向(水平或垂直)。該操作會重復執行多次(REPS)以提高計時的准確性。
垂直翻轉行:FlipImageV( )
代碼1.2中的FlipImageV( )遍歷每一列,並交換該列中互為垂直鏡像的兩個像素的值。有關Bitmap(BMP)圖像的函數存放在另一個名為ImageStuff.c的文件中,ImageStuff.h是對應的頭文件,我們將在下一章詳細解釋它們。圖像的每個像素都以「struct Pixel」類型存儲,包含unsigned char類型的該像素的R、G和B顏色分量。由於unsigned char佔用1個位元組,所以每個像素需要3個位元組來存儲。
ReadBMP( )函數將圖像的寬度和高度分別放在兩個變數ip.Hpixels和ip.Vpixels中。存儲一行圖像需要的位元組數在ip.Hbytes中。FlipImageV( )函數包含兩層循環:外層循環遍歷圖像的ip.Hbytes,也就是每一列,內層循環一次交換一組對應的垂直翻轉像素。
代碼1.2:imflip.c⋯FlipImageV( ){⋯}
對圖像的行做垂直翻轉,每個像素都會被讀取並替換為鏡像行中的相應像素。
水平翻轉列:FlipImageH( )
imf?lip.c的FlipImageH( )實現圖像的水平翻轉,如代碼1.3所示。除了內層循環相反,該函數與垂直翻轉的操作完全相同。每次交換使用「struct Pixel」類型的臨時像素變數pix。
由於每行像素以3個位元組存儲,即RGB、RGB、RGB⋯⋯因此訪問連續的像素需要一次讀取3個位元組。這些細節將在下一節介紹。現在我們需要知道的是,以下幾行代碼:
只是讀取位於垂直的第row行和水平的第col列處的一個像素。像素的藍色分量在地址img[row][col]處,綠色分量在地址img[row][col+1]處,紅色分量在img[row][col+2]處。在下一章中我們將看到,指向圖像起始地址的指針img由ReadBMP( )為其分配空間,然後由main( )傳遞給FlipImageH( )函數。
代碼1.3:imflip.cFlipImageH( ){⋯}
進行水平翻轉時,每個像素都將被讀取並替換為鏡像列中相應的像素。
⑷ 編程吃cpu單核還是多核
編程序使用的IDE工具,一般是多線程的,一邊開發代碼、一邊自動自動分析語法和提示函數用法。這就用到CPU多核性能。編譯程序時只會使用一顆CPU的單線程處理。
⑸ 如何使用ccache加快編譯
C++代碼一直以其運行時的高性能高調面對世人, 但是說起編譯速度,卻只有低調的份了。比如我現在工作的源代碼,哪怕使用Incredibuild調動近百台機子,一個完整的build也需要四個小時,恐怖!!!雖然平時開發一般不需要在本地做完整的build,但編譯幾個相關的工程就夠你等上好一段時間的了(老外管這個叫monkey around,相當形象)。想想若干年在一台單核2.8GHZ上工作時的場景 - 面前放本書,一點build按鈕,就低頭讀一會書~~~往事不堪回首。
可以想像,如果不加以重視,編譯速度極有可能會成為開發過程中的一個瓶頸。那麼,為什麼C++它就編譯的這么慢呢?
我想最重要的一個原因應該是C++基本的"頭文件-源文件"的編譯模型:
每個源文件作為一個編譯單元,可能會包含上百甚至上千個頭文件,而在每一個編譯單元,這些頭文件都會被從硬碟讀進來一遍,然後被解析一遍。
⑹ 多核與單核cpu用途比較
多核在多線程軟體(一個任務同時利用多個核心運算,如殺毒,文件壓縮,3D渲染,視頻轉換,科學運算,大型程序編譯等)或者多個很佔cpu資源的程序應用時性能比單核好很多,比如一邊在轉視頻或壓縮文件,再運行其他程序單核反應就會比較慢~如果有1G以上內存,單核性能也不錯的話,日常多任務也不會很卡,如同時開很多網頁,qq,影音,下載,文檔等,這些程序只是啟動時要用一下cpu,啟動後占很少的cpu資源。
⑺ i73930K為什麼比其它6核處理器便宜得多有什麼缺點嗎
因為主流應用沒有這個數據量。多核心、多線程CPU要發揮性能,前提是必須要有足夠多的線程。但多線程開發是個坑活,不是簡單fork出來個線程就能多線程的。數據鎖定、同步、線程間通信,全都是坑。
單核性能是上不去,但事實上是你不玩大型游戲、多開掛機,不剪視頻,不搞3D渲染,不玩虛擬機集群,不三天兩頭編譯一個GCC級別的應用,輕薄本上的4核CPU都沒什麼機會滿載,除了屏幕小點外,很多人根本不覺得輕薄本和台式機使用上有什麼區別。
只有數據量足夠大了,例如1080P 24FPS規格的視頻解碼後一分鍾有近9 GB數據,需要對如此大量的數據進行壓縮編碼的視頻剪輯;根據3D模型和紋理光源設置渲染出這個數據量的CG渲染,類似這樣的天然就是海量數據的應用,才會有大批數據可以用相同的處理過程去分批處理——然後很自然就可以用多個線程,每個線程處理一批,最後匯總結果即可。或者是超過10W個源碼文件的GCC——通常是編譯後還要用編譯出來的二進製程序再編譯一到兩次,天然就是大量任務並且每個任務可以用獨立線程處理。
需要說一下的是雖然大型3D游戲也是需要實時渲染出這個數據量的畫面,而且往往數據更大量——畢竟24 FPS的游戲體驗很差,60 FPS都不一定滿意,144 FPS還沒到頭。但大部分計算是由GPU負擔,CPU只是處理一些GPU不方便處理的計算以及運行GPU的驅動程序而已。這些GPU不方便處理的計算任務通常包括但不限於用戶輸入響應、網路數據傳輸、游戲AI等,每一項任務都可以分配給不同的線程去處理,但單項任務往往不適合再進一步拆分開來使用多個線程來處理——適合多線程處理的任務通常也適合用性能更強的GPU計算。這些任務的數量總是有限的,某些任務的計算量是很小的,因此CPU核心再多往往也無法發揮。
⑻ 淺談怎樣加快C++代碼的編譯速度
C++代碼一直以其運行時的高性能高調面對世人, 但是說起編譯速度,卻只有低調的份了。比如我現在工作的源代碼,哪怕使用Incredibuild調動近百台機子,一個完整的build也需要四個小時,恐怖!!!雖然平時開發一般不需要在本地做完整的build,但編譯幾個相關的工程就夠你等上好一段時間的了(老外管這個叫monkey around,相當形象)。想想若干年在一台單核2.8GHZ上工作時的場景 - 面前放本書,一點build按鈕,就低頭讀一會書~~~往事不堪回首。 可以想像,如果不加以重視,編譯速度極有可能會成為開發過程中的一個瓶頸。那麼,為什麼C++它就編譯的這么慢呢? 我想最重要的一個原因應該是C++基本的「頭文件-源文件」的編譯模型: 1.每個源文件作為一個編譯單元,可能會包含上百甚至上千個頭文件,而在每一個編譯單元,這些頭文件都會被從硬碟讀進來一遍,然後被解析一遍。 2.每個編譯單元都會產生一個obj文件,然後所以這些obj文件會被link到一起,並且這個過程很難並行。 這里,問題在於無數頭文件的重復load與解析,以及密集的磁碟操作。 下面從各個角度給出一些加快編譯速度的做法,主要還是針對上面提出的這個關鍵問題。 一、代碼角度 1、在頭文件中使用前置聲明,而不是直接包含頭文件。 不要以為你只是多加了一個頭文件,由於頭文件的「被包含」特性,這種效果可能會被無限放大。所以,要盡一切可能使頭文件精簡。很多時候前置申明某個namespace中的類會比較痛苦,而直接include會方便很多,千萬要抵制住這種誘惑;類的成員,函數參數等也盡量用引用,指針,為前置聲明創造條件。 2、使用Pimpl模式 Pimpl全稱為Private Implementation。傳統的C++的類的介面與實現是混淆在一起的,而Pimpl這種做法使得類的介面與實現得以完全分離。如此,只要類的公共介面保持不變,對類實現的修改始終只需編譯該cpp;同時,該類提供給外界的頭文件也會精簡許多。 3、高度模塊化 模塊化就是低耦合,就是盡可能的減少相互依賴。這里其實有兩個層面的意思。一是文件與文件之間,一個頭文件的變化,盡量不要引起其他文件的重新編譯;二是工程與工程之間,對一個工程的修改,盡量不要引起太多其他工程的編譯。這就要求頭文件,或者工程的內容一定要單一,不要什麼東西都往裡面塞,從而引起不必要的依賴。這也可以說是內聚性吧。 以頭文件為例,不要把兩個不相關的類,或者沒什麼聯系的宏定義放到一個頭文件里。內容要盡量單一,從而不會使包含他們的文件包含了不需要的內容。記得我們曾經做過這么一個事,把代碼中最「hot」的那些頭文件找出來,然後分成多個獨立的小文件,效果相當可觀。 其實我們去年做過的refactoring,把眾多DLL分離成UI與Core兩個部分,也是有著相同的效果的 - 提高開發效率。 4、刪除冗餘的頭文件 一些代碼經過上十年的開發與維護,經手的人無數,很有可能出現包含了沒用的頭文件,或重復包含的現象,去掉這些冗餘的include是相當必要的。當然,這主要是針對cpp的,因為對於一個頭文件,其中的某個include是否冗餘很難界定,得看是否在最終的編譯單元中用到了,而這樣又可能出現在一個編譯單元用到了,而在另外一個編譯單元中沒用到的情況。 之前曾寫過一個Perl腳本用來自動去除這些冗餘的頭文件,在某個工程中竟然去掉多達了5000多個的include。 5、特別注意inline和template 這是C++中兩種比較「先進」的機制,但是它們卻又強制我們在頭文件中包含實現,這對增加頭文件的內容,從而減慢編譯速度有著很大的貢獻。使用之前,權衡一下。
⑼ 頻率高線程少性能低和頻率低線程多性能高那個好
IPC
初接觸CPU的小白可能會好奇,為什麼R5-5600X頻率才4.6,單核卻能在一眾頻率5.0+的i7、i9之上?以前的FX-9590頻率也飆到5.0,為什麼卻那麼弱?
其實CPU有一個指標叫「IPC」,全稱Instruction Per Clock,它指CPU每一個頻率周期里處理的指令數量。小白可以簡單粗暴記憶——
CPU性能=頻率*IPC
IPC愈高,基本意味著CPU架構愈優秀。但沒有人會標注IPC的具體數值,一般只有Intel和AMD開發布會的時候,才會公布IPC「相比上一代提升了多少」——
CPU規格表
Intel桌面處理器規格表www.mydrivers.comAMD桌面處理器規格表www.mydrivers.com
單核性能
直接用規格表裡的「加速頻率」乘以對照表裡的百分比,即可計算出來。
i9-10850K,單核性能為5.2;
E3-1230V2,單核性能為3.7*0.85≈3.15;
X3440超頻3.6,單核性能為3.6*0.77≈2.77;
R7-5800X,單核性能為4.7*1.27≈5.97;
R5-2600,單核性能為3.9*0.93≈3.63;
X4-955超頻4.0,單核性能為4.0*0.61=2.44。
單核性能主要影響:軟體開關速度;較簡單的運算(如Excel公式、Python腳本);大多數普通應用軟體;游戲幀數的上限(前提是顯卡足夠強)。
多核性能
注意規格表裡並沒有標出「全核加速頻率」,還需要自己網路。Intel的全核加速頻率是有明確標識的,用Aida64可以查到,如i9-10850K為4.8;AMD則沒有明確標識,需要通過一些測評報告才能查到,如R7-5800X為4.5。
多核性能用「全核加速頻率」乘以核心數,有超線程的時候,Intel一個超線程≈0.25個核心;AMD的超線程效率稍高,可以≈0.3個核心。然後再乘以對照表裡的百分比。
i9-10850K全核加速頻率4.8,10核20線相當於12.5核,多核性能為12.5*4.8=60;
E3-1230V2全核加速頻率3.5,4核8線相當於5核,多核性能為3.5*5*0.85≈14.88;
X3440超頻3.6,4核8線相當於5核,多核性能為3.6*5*0.77=13.86;
R7-5800X全核加速頻率4.5,8核16線相當於10.4核,多核性能為4.5*10.4*1.27≈59.44;
R5-2600全核加速頻率3.7,6核12線相當於7.8核,多核性能為3.7*7.8*0.93≈26.84;
X4-955超頻4.0,4核,多核性能為4.0*4*0.61=9.76。
多核性能主要影響:軟體多開數目(前提是內存足夠大)、較復雜的運算(如壓縮解壓縮、代碼編譯)、視頻渲染等較重度應用、游戲幀數的下限(前提是單核沒過分低)。
回到一開始的問題
Q:R5-5600X還是R7-3700X?
A:單核基本不用算,5600X完勝。多核5600X是4.15*7.8*1.27≈41.11,3700X是3.95*10.4*1.07≈43.96,差距非常小。所以絕大多數時候只推薦5600X。除非你確定你的工作能優化到16個線程(PR、C4D)才考慮3700X。
Q:R7-5800X還是R9-3900X?
A:單核基本不用算,5800X完勝。多核5800X是4.5*10.4*1.27≈59.44,3900X是4.05*15.6*1.07≈67.60,還是有一定差距。所以應根據自己的具體需求選擇。
Q:想買i5-10600KF,有必要上Z主板超頻嗎?
A:i5-10600KF默認加速頻率是單核4.8全核4.5,體質普遍較差,超頻到4.8基本到頂了。單核無提升,多核只提升4.8/4.5-1≈6.7%,所以沒必要超頻啦。
Q:i5-4590不夠用了,要升級i7-4790K再超頻用嗎?
A:i7-4790K用一般的主板和散熱,超頻到4.6基本到頂了,4核8線相當於5核,單核4.6*0.91≈4.19,多核4.6*5*0.91=20.93。和它規模相同的i3-10100F單核4.3,多核4.1*5=20.5。整體差不多,功耗少很多,不用折騰超頻,板+u+新內存也貴不到哪裡去。所以建議不要升級,直接換新平台叭。
這種判斷的局限性
IPC是會隨頻率衰減的,實際上本文的判斷方法,在單核4GHz上下最為准確。頻率過分高的時候,會比實際偏高,比如你算出來5.8的實際可能更貼近5.5;頻率過分低的時候,會比實際偏低,比如你算出來2.2的實際可能更貼近2.5。老架構超頻後的表現同理,i5-2550K超頻到5.0後,算出來單核多核都比i3-9100F強,但是實際表現差不多。
有些應用依賴內存緩存還有匯流排的性能,導致實際會在你的判斷基礎上打折扣。比如AMD Zen之後的平台內存控制器外掛,導致延遲偏高,一般要搭配3200內存玩游戲,才能達到Intel同性能搭配2666內存的效果。比如E5450的前端匯流排帶寬上限較低,導致GTA5一類較新游戲的表現會明顯受限,反而不如算出來不如它的X4-955。
有些應用依賴或會調用較新指令集,這種情況下不能以判斷論處。比如X4-955沒有SSE4.2指令集,而最終幻想15依賴這個,到頭來游戲你打都打不開。i7-870缺少AVX指令集,而格式工廠會調用這個去加速,到頭來你剪片速度會很慢,比i3-2120都慢。
尚未發布的11代酷睿台式機,119%屬於根據10代10nm筆記本Ice Lake表現推算。實際結果應該會比這個稍低,畢竟台式機還是14nm,且IPC會隨頻率衰減。
⑽ 阿里平頭哥宣布,自研處理器已成功落地,它的性能如何
阿里巴巴宣布旗下的平頭哥半導體完成了安卓10對RISC-V的移植並開源了全部相關代碼。從平頭哥社區發布的信息來看,安卓10系統已經可以在玄鐵910晶元上流暢運行。至於玄鐵910,則是前年阿里巴巴旗下的平頭哥半導體發布的一款號稱是業界最強的RISC-V處理器內核IP。資料顯示,玄鐵910單核性能達到7.1 Coremark/MHz,主頻達到2.5GHz,比當時業界最好的RISC-V處理器性能高40%以上。據介紹,玄鐵910可以用於設計製造高性能端上晶元,應用於5G、人工智慧以及自動駕駛等領域。