之前在推特/X上与@corsix交流后,作者发布了字节直方图实现但未解释,本文旨在弥补这一不足。
- pospopcnt:把 N 个 k 位字的数组视为 N 行 k 列的位矩阵,行的普通 popcnt 容易计算,pospopcnt 是按位置计数,即列求和。可通过垂直进位保存加法器减少“重垂直求和”,此技术在Efficient Computation of Positional Population Counts Using SIMD Instructions中有讨论。该技术产生的中间结果格式较尴尬,若有四个 512 位向量作为中间结果且计算 64 位 QWORD 的 pospopcnt,每个向量现在有 8 组 QWORD,第 i 个向量中每个 QWORD 的第 k 位对 pospopcnt 的第 k 位贡献值为 2i。使用 GF2P8AFFINEQB 和 VPERMB 可重新组合向量中的位,方便用 VPOPCNTB 求和,然后移位相加。有了 pospopcnt 可通过 1 << data 转换数据后制作直方图。
- Binning:前文描述的 pospopcnt 只能产生 64 个计数,适合 0 到 64 范围的数据直方图。对于字节,可将 pospopcnt 推广到 256 个位置计数,早期算法原型就是这样做的,但这种方式会导致左移较尴尬且需减少/求和每 256 位只有 1 位为设置的向量,64 位情况已存在大多是求和 0 的问题,256 位情况更糟。作者曾认为这限制了“pospopcnt 直方图算法”的应用范围到 6 位数据,后来想到将不在 0 - 64 范围的数据分成 0 - 64 的 bin,基于 VPCOMPRESSB 可快速完成,这样虽增加了数据分箱时间,但使用 64 位 pospopcnt 比其缓慢的 256 位推广更有效。
- 根据作者在 Intel 11600K(Rocket Lake)上的基准测试,该算法在随机和非随机数据上比 Powturbo 的 hist_8_64 快近两倍,速度约为 8.8GB/s 对 4.6GB/s,对数据模式大多免疫(不像古老的 hist[data[i]]++算法在某些模式数据下会变慢)。在 Zen5(9700X)上也做了基准测试,结果显示某些模式数据会增加 Zen5 上的性能,但在 11600K 上未观察到该效果。Joern Engel 和 Curtis Bezault 也发现了一些改进。
- 下方是总结算法主要组件的图表:

**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。