http://www.1point3acres.com/bbs/thread-212960-1-1.htmlhtml
第二輪白人小哥,一開始問了一道至今不懂的問題,好像是給一個vector<uint8_t> nums, 而後又給一個256位的vector<int> counts,遍歷nums,而後counts[nums]++,問如何進行優化,提示說要用到CPU cache之類的東西(徹底不知道)。小白哥見我懵逼,後來又給了一道3sum,迅速作出。
ide
uint8_t input[102400]; uint32_t count[256]; void count_it() { for (int i = 0; i < sizeof(input) / sizeof(input[0]); i++) { ++count[input[i]]; } }
how to optimize? possible points to consider:oop
a) target "count" array size is 4B*256=1KB, which can fit into L1 cache, so no need to worry about that;fetch
b) input array access is sequential, which is actually cache friendly;ui
c) update to "count" could have false sharing, but given it's all in L1 cache, that's fine;spa
d) optimization 1: the loop could be unrolled to reduce loop check;code
e) optimization 2: input array could be pre-fetched (i.e. insert PREFETCH instructions beforehand);htm
for (int i = 0; i < sizeof(input) / sizeof(input[0]);) { // typical cache size is 64 bytes __builtin_prefetch(&input[i+64], 0, 3); // prefetch for read, high locality for (int j = 0; j < 8; j++) { int k = i + j * 8; ++count[input[k]]; ++count[input[k+1]]; ++count[input[k+2]]; ++count[input[k+3]]; ++count[input[k+4]]; ++count[input[k+5]]; ++count[input[k+6]]; ++count[input[k+7]]; } i += 64; }
(see https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Other-Builtins.html for __builtin_prefetch)blog
f) optimization 3: multi-threading, but need to use lock instruction when incrementing the count;rem
g) optimization 4: vector extension CPU instructions: "gather" instruction to load sparse locations (count[xxx]) to a zmmx register (512bit, 64byte i.e. 16 integers), then it can process 16 input uchar8_t in one go; then add a constant 512bit integer which adds 1 to each integer. corresponding "scatter" instruction will store back the updated count.
第二輪白人小哥,一開始問了一道至今不懂的問題,好像是給一個vector<uint8_t> nums, 而後又給一個256位的vector<int> counts,遍歷nums,而後counts[nums]++,問如何進行優化,提示說要用到CPU cache之類的東西(徹底不知道)。小白哥見我懵逼,後來又給了一道3sum,迅速作出。