iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
AI Engineering

GPU很忙?他真的有在做事嗎?系列 第 10

Day 10|profile 到手,先體檢照表操課

  • 分享至 

  • xImage
  •  

開小黃的都知道,身體是本錢,我每年乖乖去做一次健檢。報到、抽血、量血壓、照超音波,流程固定,半小時走完,報告直接告訴你哪裡紅字、該掛哪一科。醫生不會一見面就把你推進開刀房,一定先照表走完這一輪。

今天,換你坐到醫生那一側。手上那份 profile 就是躺在檢查台上的病人,我要給你的,就是那張檢查表。

Day 4 到 Day 9,你學會了開檔讀圖、用 stats 算帳、自己錄、圈三圈、掛路牌、進容器。功夫都在了,但散裝。散裝的下場我看太多次,profile 一打開,GUI 裡東點西點逛了半小時,看到一個可疑的就撲上去,最後修了一個不痛不癢的地方。今天把散裝的招收成一套 SOP,固定順序、固定產出,三分鐘跑完,你就講得出這份 job 健不健康、該掛哪一科。

為什麼要照表操課

固定順序有三個好處,都很實際。

第一,可重複。同一套順序跑一百份 profile,你的判斷品質是穩的,不會今天狀態好就看得細、明天累了就漏看 memcpy。第二,可比較。每份都產出同一張病歷首頁,優化前後一對就知道有沒有進步,這是 Day 27 之後做 diff 的地基。第三,可交接。你休假,同事照表也能跑出同一份結論,這叫工程,憑感覺的那叫通靈。

還有一條要先立好的界線,體檢不是治療。今天這套流程只回答"哪裡可疑",不動手修。看到可疑就想撲上去修,是這行最貴的壞習慣,因為你還沒確診。先體檢,再細查,最後才開刀,這個順序我們整季不變。

第 0 步,驗檢體

老規矩,Day 6 的三秒檢查,先確認手上這份錄影是好的:

ls -lh report.nsys-rep                                  # MB 量級,不該是 GB
nsys stats --report cuda_gpu_kern_sum report.nsys-rep   # 表上要有 kernel

空表就別往下走了,八成是 Day 9 的第四道門,回去補 fork 的旗標;再不然就是 Day 7 的窗圈錯了位置,窗裡根本沒幾顆 kernel。檢體不對,後面驗得再仔細都是白工。

第 1 步,四張表算總帳

接著把 Day 5 的報表家族一次點齊。--report 吃逗號,四張一行搞定:

nsys stats --report cuda_gpu_kern_sum,cuda_gpu_mem_time_sum,nvtx_sum,cuda_api_sum \
  report.nsys-rep

順帶一提,nsys stats 不帶 --report 會直接跑一整套預設報表,七八張全上。整套全驗不是不行,但體檢要快,像抽血一次抽四管,夠分診就好。四張表各帶走一個數字:

  • kern_sum,最肥的 kernel 是誰、佔幾成。第一名超過三成,它就是你的 80/20 下手處(Day 13)。
  • mem_time_sum,搬運的帳。小心這張表的 Time(%) 是 memcpy、memset 自家人互比,加起來 100%,不代表佔整體多重;要知道搬運吃掉全局幾成,拿它的 Total Time 去跟 kern_sum 的總時間並排比。搬運時間到了 kernel 總時間的一兩成,就把死法二(搬不完)圈個紅字(Day 16)。
  • nvtx_sum,你 Day 8 掛的牌在這裡兌現,forward、backward、data 各佔多少。backward 是 forward 兩倍上下算正常,三倍先想 activation checkpointing;data 段肥,資料那格先標紅(Day 16)。別忘了 Day 8 的提醒,這張表量的是 CPU 側的 range,是下單速度;要對 GPU 的真實出貨帳,拿 nvtx_gpu_proj_trace 投影版再核一次。
  • api_sum,CPU 側的帳。cudaLaunchKernel 次數爆量配上滿場 µs 級小 kernel,launch-bound,圈紅字(Day 15);cudaDeviceSynchronize 吃掉一大截,CPU 在乾等,同步太多。

讀表還有兩個內行的看法。第一,別只看 Total Time 那欄,配著 Instances 一起讀。總時間高但 Instances 少,是單顆肥 kernel,去 Day 13 修那一顆;總時間高是靠 Instances 爆量堆出來、每顆平均才幾 µs,那是 launch 海,修單顆沒用,要去 Day 15 想辦法把它們併起來。同一欄總帳,兩種完全不同的病。第二,掃一眼 StdDev。同名 kernel 跑了三千次,標準差卻大得離譜,代表它的耗時不穩,常見原因是 shape 一直在變(Day 7 講過的 autotune 暖不完那掛)或跟別人搶資源,這種不穩定本身就是線索。

這裡再教一手進階的,把 mem_time_sum 換成它的兄弟 cuda_gpu_mem_size_sum 再跑一次,一張給時間、一張給 bytes,同一種操作對同一種操作除,就是那種搬運的有效頻寬;要對 PCIe 的帳,挑 HtoD 那列算,別把 DtoD 這種卡上自己搬的混進來。PCIe 4.0 x16 的理論值是 32 GB/s,實務打個八折上下;你要是算出來只有個位數 GB/s,八成踩到 pageable memory(Day 5 那條 analyze 規則的老朋友),先用紅筆圈起來。

最後一手,體檢結果留底:

nsys stats --report cuda_gpu_kern_sum --format csv --output . report.nsys-rep

--format csv--output 會把表寫成檔案。每次體檢都留一份 CSV,你就有了 baseline,下個月 job 變慢的時候,兩份 CSV 一比,誰變肥了一目了然。沒有 baseline 的體檢,每次都是第一次看診。

第 2 步,讓 analyze 掃一輪線索

第二步交給 Day 5 的專家規則:

nsys analyze report.nsys-rep

它會把常見毛病自動掃一遍,多餘的同步、pageable memcpy、GPU 發呆時段,直接點名給你。把它的輸出當成"線索清單"抄進病歷,但記得 Day 5 立的規矩,analyze 給的是線索不是定論,它說有 pageable memcpy 是事實,值不值得修要看它佔的比例,比例就在你第 1 步那幾張表裡。兩步互相對照,才不會被單一工具牽著走。

第 3 步,開 GUI 看結構

前兩步是量,最後一步是看,Day 4 的三個動作直接上,放大、找一圈、收列。這一步要回答的是表格答不了的問題,事情發生的形狀順序

照 Day 4 的三件事掃,kernel 密不密、空白在哪、memory 條多不多。有掛 NVTX 的話樹直接展開,Day 8 教的三個現象順手看掉,fwd/bwd 比例、圈與圈之間有沒有縫、optim 段是不是小 kernel 海。表格告訴你 memcpy 佔 12%,GUI 告訴你這 12% 是攤平在整圈、還是全堵在每圈開頭,同一個數字、兩種病,處方完全不同。

到這裡,三分鐘用完,體檢結束。

三分鐘體檢 SOP 四步:第 0 步驗檢體、第 1 步四張表算總帳、第 2 步 analyze 掃線索、第 3 步 GUI 看結構,固定順序、固定產出

產出,一張病歷首頁

體檢的產出固定是一張卡,五個欄位。拿 Day 5 那份 8 卡訓練的數字(示意)填給你看:

病歷首頁 · baseline.nsys-rep · 8×GPU
────────────────────────────────────
GPU idle        ~20%   ← 紅字:發呆
top kernel      flash attention ~30%
memcpy          ~8%(頻寬正常)
fwd : bwd       1 : 2.1(正常)
NCCL            ~15%   ← 紅字:通訊
────────────────────────────────────
分診:先掛發呆,再掛通訊

五個欄位長期固定,每份 profile 都填同一張,這就是可比較、可交接的具體長相。最下面那行分診才是整張卡的結論,它決定你下一步掛哪一科。

老實交代一格,idle 那格是五格裡最難填的。Day 5 掀蓋子時講過,真 idle 要把所有 stream 的 kernel 區間做聯集再拿 wall time 去減,nsys stats 沒有一張現成的表直接吐這個數字。所以目前這格的填法是兩個來源夾出來的,analyze 的 GPU starvation 線索給你"有沒有大段發呆",GUI 放大目測給你"洞大概佔多少"。夾出一個粗估值先寫上,夠分診用了。想要一鍵拿到精確 idle,這正是那些疊在 nsys 上面的工具最有價值的地方之一,Day 12 見。

分診表,五條線

分診的邏輯就是 Day 2 三種死法的實戰版,對著症狀掛號:

  • 空白多,圈與圈之間規律空一截,或圈內整段的洞,掛發呆(Day 14)。問診時發現縫是 loader 害的,轉診到資料那條(Day 16)。
  • kernel 密到爆但全是 µs 級小不點,api_sum 的 launch 次數又爆量,掛launch,Day 15。
  • memcpy 佔比高或頻寬爛,掛資料,Day 16。
  • NCCL 佔比高,八張卡在互等,掛通訊,Day 18–19。
  • 以上都不明顯,kernel 又肥又滿、乖乖在算,恭喜,它可能真的在做事,但做得有多有效?那要問 MFU,掛 Day 17。

病歷首頁示意卡:五個固定欄位,GPU idle 與 NCCL 兩格圈了紅字,右側發呆、launch、資料、MFU、通訊五條分診線各自掛號到 Day 14 至 Day 18–19,紅字的兩條標上先掛、再掛

注意一件事,多數真實的 profile 會同時掛好幾科,像上面那張示意卡就同時圈了發呆跟通訊兩個紅字。分診表幫你排的是順序,不是唯一答案,佔比最大的先查,這也是 80/20。

三個常見的體檢誤判

檢查表給了,再把三個最常見的誤判先幫你踩掉。

第一個,拿暖機段做體檢。Day 7 苦口婆心講過的事,要是你的窗圈到了前幾十步,這份體檢從頭到尾都是暖機的樣子,卡上每個數字都失真,分診自然掛錯科。體檢之前先確認窗的位置,圈錯了整份作廢重錄,別捨不得。

第二個,拿兩份不同 workload 的卡互比。上週 batch size 32、這週 64,兩張病歷首頁一比,哀嚎怎麼變慢了,那不是病,是你換了病人。baseline 要有意義,workload 得釘死,同模型、同 batch、同資料、同機器,動了哪個就在卡上註記哪個。留底的 CSV 檔名裡也該帶著這些資訊,日期加 commit hash 是最低消費,不然一個月後你自己都不知道那份 baseline 是誰。

第三個,只看百分比、不換算絕對值。memcpy 佔 8% 聽起來無害,但一圈要是跑十秒,8% 就是 0.8 秒,讓它跑一整天就是將近兩個鐘頭的白工,乘上 Day 1 那張雲端帳單的時薪,它就從"報告上沒紅字"變成一筆看得見的錢。反過來,佔比 20% 的東西若絕對值只有幾 ms,修它的工程時間可能比它一年浪費的錢還貴。百分比拿來分診,絕對值拿來決定值不值得動手,兩個都要看。

小結與明天

Part B 到今天收官。五天下來你會錄(Day 6)、會圈(Day 7)、會標(Day 8)、進得了容器(Day 9),今天再把 Day 4 以來的所有讀法收成一套三分鐘 SOP,驗檢體、四張表、analyze、GUI,產出一張病歷首頁,照分診表掛號。從此 profile 到手,你不再是亂翻報告的實習醫師,是照表操課的資深主治。

明天開始換檔。前面十天都在練基本功,接下來一週,我們回到 Day 4 那份 8 卡 Megatron 的錄影,把它當成一個要好好會診的病人,一天看一個病灶,把每條分診線真的走完。明天 Day 11,先從讀圖的三件事開始,在真檔上把空白、kernel bar、stream 一條條認回來。

檢查表發給你了。明天,開始會診。

參考資料


上一篇
Day 9|容器裡錄不到?不是你不會按快門,是門沒開
下一篇
Day 11|會診第一天,把片子掛上燈箱,Let's check it
系列文
GPU很忙?他真的有在做事嗎?11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言