算術強度(arithmetic intensity)
想像一位送貨司機,只按送達的包裹計酬,卻必須開車到遙遠的倉庫去取每一趟貨。如果每趟倉庫之行只取回一個小包裹,司機整天耗在路上、幾乎送不了什麼——車程主宰一切。如果每趟把廂型車裝滿數百個包裹,車程就被攤平,司機很有生產力。算術強度對一項計算問的是同一個問題:你每從記憶體拖上一個位元組,能榨出多少有用的算術運算?
正式地說,算術強度是「執行的浮點運算數」與「往返主記憶體搬動的位元組數」之比,常寫成 I = flops / bytes。向量加法 c = a + b 讀 16 位元組(兩個 double)、寫 8 位元組,產出 1 次浮點運算,故強度約每位元組 1/24 次浮點運算——很低;它因算術不足,完全受記憶體餵資料速度所限(記憶體受限)。反觀稠密矩陣乘法做 2*n^3 次浮點運算,卻(在良好分塊下)只搬動 n^2 量級的資料,故強度隨 n 增長——很高;它能讓算術單元忙個不停,受限於原始計算速度(計算受限)。分界線、那個「脊點」,是機器尖峰浮點速率等於其尖峰記憶體頻寬乘以強度之處。
算術強度是這麼一個數,它在你動手最佳化之前就告訴你:你是在跟算術單元搏鬥、還是跟記憶體系統搏鬥——從而哪些最佳化有可能幫上忙。若某核心是記憶體受限(低強度),買更快的處理器、或手工調內層迴圈都沒用;你必須改以重用資料(分塊、融合運算)來提升強度,或乾脆搬動更少資料。若它是計算受限(高強度),那麼向量化與更快的算術就有回報。在屋頂線模型上作圖時,強度就是橫軸,它把一個核心擺在頻寬天花板或計算天花板之下。
依強度排三個核心:向量加法(約 0.04 flop/byte,深度記憶體受限)、矩陣對向量積 A*x(約 0.25 flop/byte,仍記憶體受限)、分塊矩陣對矩陣乘法(強度隨塊大小增長,可超過 10 flop/byte 而成為計算受限)。只有最後者能逼近機器尖峰浮點速率;前兩者無論算術多巧妙,都被記憶體頻寬封頂。
強度等於每搬動一位元組的浮點運算數;它決定你的牆是記憶體還是算術。
強度取決於什麼算作「搬動的資料」——同一演算法,若資料留在快取,強度遠高於從 DRAM 串流時。所以一個核心在大問題上可能記憶體受限,在能放進快取的小問題上卻計算受限;這個數不是數學本身的固定性質。