群友讨论第一期, 这个栏目要多谢群友交流

本期鸣谢群友 @核聚变引擎 @mwish

群友核聚变引擎 提问

这段代码有办法做simd加速吗,感觉无解 https://gcc.godbolt.org/z/GjjEfz1e8

代码如下

#include <cstdint>

const int M = (1 << 14);
uint16_t bins[64] = {0};
uint8_t data[M] = {0};

// 统计 data 中 0~63 的频数,不考虑高 2 位
void histgram(uint16_t *bins, uint8_t *data) {
    for (int i = 0; i < M; i++) {
        uint8_t x = data[i] & 0x3f;
        bins[x]++;
    }
}

这种计算是统计型,关键是统计M输入到64,不是多对1类型的计算,比如popcnt

优化角度无非是攒批/分片

使用chatgpt帮咱写了一个版本

void histgram_avx(uint16_t *bins, uint8_t *data) {
    __m256i mask = _mm256_set1_epi8(0x3F);
    for (int i = 0; i < M; i += 32) {
        __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(data + i));
        chunk = _mm256_and_si256(chunk, mask);

        uint8_t tmp[32];
        _mm256_storeu_si256(reinterpret_cast<__m256i*>(tmp), chunk);

        for (int j = 0; j < 32; ++j) {
            bins[tmp[j]]++;
        }
    }
}

这种加速其实效果非常有限,M也不大,性能提升并不明显

群友mwish提供了一个分片的版本

using Bucket = std::array<uint16_t, 64>;

// 统计 data 中 0~63 的频数,不考虑高 2 位
std::array<Bucket, 8> histgram_mwish(uint16_t *bins, uint8_t *data) {
    std::array<Bucket, 8> temp_bins;
    for (int i = 0; i < M / 8; i++) {
        for (int idx = 0; idx < 8; ++idx) {
            uint8_t x = data[i * 8 + idx] % 64;
            temp_bins[idx][x]++;
        }
    }
    return temp_bins;
}

我压测了一版数据,机器是2019 mbp 性能一般,结果如下

2024-07-07T18:16:00+08:00
Running ./build/bm_histgram
Run on (12 X 2600 MHz CPU s)
CPU Caches:
  L1 Data 32 KiB
  L1 Instruction 32 KiB
  L2 Unified 256 KiB (x6)
  L3 Unified 12288 KiB
Load Average: 2.84, 3.07, 2.77
--------------------------------------------------------------------------------
Benchmark                                      Time             CPU   Iterations
--------------------------------------------------------------------------------
BM_histgram_mwish/iterations:10000000       7065 ns         7019 ns     10000000
BM_histgram_base/iterations:10000000        6836 ns         6769 ns     10000000
BM_histgram_avx/iterations:10000000         7228 ns         7179 ns     10000000

能看到性能差异基本可以无视,优化反而还慢了

压测代码在这里

有什么错误或者有什么改善的思路,欢迎提出