accParaCounter.cpp中的嵌套循環結構可以用來控制循環并行性,是以可以控制并行資源消耗。
大多數并行程式設計人員遵循在系統中利用最大并行性來實作最高性能的方法。
大量線程背後的思路是給予并行排程器盡可能多的線程以供排程,進而最大化地利用所有計算資源。GPU程式設計人員喜歡用占有率(occupancy)作為線程并行度的度量。高占有率意味着排程器有更多的激活線程以供調用,是以有機會實作更高性能。
高占有率并不一定轉為最快的應用性能。指令級并行(Instruction level parallelism,ILP)通過較少的線程來保持處理器(或GPU)忙碌以隐藏線程等待時間,線程數越少,消耗的資源和開銷越少。指令級并行同樣可以獲得高性能。但是,程式設計人員必須安排好計算以確定最好地使用并行硬體。使用ILP的原因簡單卻有效:使用較少的線程意味着每個線程可以使用更多的資源(Volkov, 2010)。
這個結論同樣适用于OpenACC,用來控制并行資源的使用。不同于OpenMP,OpenACC不提供類似omp_get_thread_num()機制來确定線程的身份,也不提供類似omp_get_num_thread()機制來找出并發線程總數。是以,無法寫出可以控制其并行資源使用的類。相反,至少OpenACC 2.5規範中,OpenACC開發人員必須使用嵌套循環結構來顯式控制在其程式中如何使用并行資源。
例如,程式accParaRNG.cpp并行地利用多個順序随機數生成器。為了成功執行,程式必須保證同時隻有一個線程使用随機數生成器。否則的話,内部更新的随機數生成器狀态資訊可能會損壞。不能用單個原子操作來更新種子區域,在OpenACC中唯一確定正确的操作是使用一個嵌套循環集。
如圖1-23和1-24所示,accParaNRG.cpp代碼使用任務并行和本章讨論的OpenACC建構,以及帶進位乘法(multiply-with-carry, MWC)随機數生成器。George Marsaglia發明了MWC随機數生成器,基于從兩個到數千個随機選擇的種子值的初始集合來生成随機整數序列(Marsaglia & Zaman,1991)。MWC方法的主要優勢是可以用少量C++代碼實作,并且隻有整數運算。MWC仍然主導快速生成随機數序列。讀者可以用其他更精細的随機數生成器來替換accParaNRG.cpp中的算法,例如廣泛使用的梅森絞扭器(Matsumoto & Nishinura, 1998)和Dieharder随機數測試套件(Brown, 2016)。
組合圖1-23和圖1-24中的代碼,放到accParaRNG.cpp中。編譯accParaRNG.cpp成PGI統一的二進制,在CPU和GPU上的測試結果如圖1-25所示: