展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 硬件相关 > popcnt指令的前世今生探索

popcnt指令的前世今生探索

最近群聊里传了一个面试题实现统计1的个数(汉明权重hammingWeight),使用popcnt的算法对硬件不友好,有无绕过的思路显然这个哥们的第一个实现是代码语言:javascript代码运行次数:0运行复制inthammingWeight_popcnt(uint64_tn){return__builtin_popcountll(n);}当然c++20也支持https://en.cppreference.com/w/cpp/numeric/popcount一行,觉得自己很帅,当然面试官不

popcnt的前世今生?

最近群聊里传了一个面试题

实现统计1的个数(汉明权重 hammingWeight),使用popcnt的算法对硬件不友好,有无绕过的思路

显然这个哥们的第一个实现是

代码语言:javascript代码运行次数:0运行复制
int hammingWeight_popcnt(uint64_t n) {  return __builtin_popcountll(n);}

当然c++20也支持 https://en.cppreference.com/w/cpp/numeric/popcount

一行,觉得自己很帅,当然面试官不喜欢,提示不要用popcnt,所谓的对硬件不友好指的应该是部分硬件没有这个指令

又或者性能原因?难道GPU上的popcnt性能很差?按下不表

直接贴实现

代码语言:javascript代码运行次数:0运行复制
int hammingWeight(uint64_t n) {    int ret = 0;    while (n) {        n &= n - 1;        ret++;    }    return ret;}

其实开启 O2 加上 -march=native,大家都会生成相同的popcnt, 早在2016年Lemire大哥就发现了

https://lemire.me/blog/2016/05/23/the-surprising-cleverness-of-modern-compilers/

附上llvm检测的代码 https://github.com/llvm-mirror/llvm/blob/f36485f7ac2a8d72ad0e0f2134c17fd365272285/lib/Transforms/Scalar/LoopIdiomRecognize.cpp#L960

只开O2可能保守场景不会生成popcnt

如果不用popcnt,代码的性能和popcnt差距大吗?或者说,popcnt有危害吗?比如延迟高?

直接上llvm-mca分析 https://godbolt.org/z/odox8Wdr5

首先插入一个简单粗暴的教程,如何看懂llvm-mca https://llvm.org/docs/CommandGuide/llvm-mca.html

就是机器码分析器,模拟机器码执行效果,我们不用装llvm-mca,直接用godbolt内置的工具。代码已经生成好了

直接贴popcnt代码的结果吧

代码语言:javascript代码运行次数:0运行复制
Iterations:        100Instructions:      200Total Cycles:      57Total uOps:        200Dispatch Width:    6uOps Per Cycle:    3.51IPC:               3.51Block RThroughput: 0.5Instruction Info:[1]: #uOps[2]: Latency[3]: RThroughput[4]: MayLoad[5]: MayStore[6]: HasSideEffects (U)[1]    [2]    [3]    [4]    [5]    [6]    Instructions: 1      1     0.25                        popcnt rax, rdi 1      5     0.50                  U     retResources:[0]   - Zn3AGU0[1]   - Zn3AGU1[2]   - Zn3AGU2[3]   - Zn3ALU0[4]   - Zn3ALU1[5]   - Zn3ALU2[6]   - Zn3ALU3[7]   - Zn3BRU1[8]   - Zn3FPP0[9]   - Zn3FPP1[10]  - Zn3FPP2[11]  - Zn3FPP3[12.0] - Zn3FPP45[12.1] - Zn3FPP45[13]  - Zn3FPSt[14.0] - Zn3LSU[14.1] - Zn3LSU[14.2] - Zn3LSU[15.0] - Zn3Load[15.1] - Zn3Load[15.2] - Zn3Load[16.0] - Zn3Store[16.1] - Zn3StoreResource pressure per iteration:[0]    [1]    [2]    [3]    [4]    [5]    [6]    [7]    [8]    [9]    [10]   [11]   [12.0] [12.1] [13]   [14.0] [14.1] [14.2] [15.0] [15.1] [15.2] [16.0] [16.1] 0.33   0.33   0.34   0.50   0.33   0.33   0.34   0.50    -      -      -      -      -      -      -     0.33   0.33   0.34   0.33   0.33   0.34    -      -     Resource pressure by instruction:[0]    [1]    [2]    [3]    [4]    [5]    [6]    [7]    [8]    [9]    [10]   [11]   [12.0] [12.1] [13]   [14.0] [14.1] [14.2] [15.0] [15.1] [15.2] [16.0] [16.1] Instructions: -      -      -      -     0.33   0.33   0.34    -      -      -      -      -      -      -      -      -      -      -      -      -      -      -      -     popcnt rax, rdi0.33   0.33   0.34   0.50    -      -      -     0.50    -      -      -      -      -      -      -     0.33   0.33   0.34   0.33   0.33   0.34    -      -     retwarning: found a return instruction in the input assembly sequence.note: program counter updates are ignored.

先记下这几个数字

代码语言:javascript代码运行次数:0运行复制
Iterations:        100Instructions:      200Total Cycles:      57Total uOps:        200Dispatch Width:    6uOps Per Cycle:    3.51IPC:               3.51Block RThroughput: 0.5

重点参数 是IPC, uOps Per Cycle, 和 Block RThroughput (Block Reciprocal Throughput).

• IPC就是模拟的总指令数字除以总cycle数 一般这个就表示吞吐了 Instructions / Total Cycles 显然这个值越高越好• Block RThroughput (Block Reciprocal Throughput) 就是Block Throughput(每个cycle能运行几次block)的倒数 就是 Total Cycles / Iterations 每次运行能用几个cycle的意思,显然,这个值越低越好• Instructions / Iterations 代表每次迭代能执行几次指令 显然 Instructions / Iterations / Block RThroughput = IPC 这个数比直接算IPC大点(有误差。。。。)你就当他是无影响的最大IPC吧• (循环数据引用问题可能导致影响。假设循环展开无影响)• uOps Per Cycle,就是模拟的微指令数总和除以总cycle数字 Total uOps/ Total Cycles ,这个和IPC含义差不多,显然这个值越高越好,但是要关注Dispatch Width - uOps Per Cycle 差值, Dispatch Width 表示最大发射指令的并行带宽,相当于资源限制了,uOps Per Cycle表示实际模拟使用的带宽,显然越接近Dispatch Width越说明资源受限制,利用率太高了,相当于CPU高了,需要找到瓶颈来源• 剩下的是执行模拟以及在哪里卡了,具体分析可以用-bottleneck-analysis,得本地搞了godbolt貌似不能玩

好了,根据上面的godbolt结果,直接把数据差异对比一下

另外 网上搜到了google的两个实现,把数据补充上 https://godbolt.org/z/9nsczeT5c

代码语言:javascript代码运行次数:0运行复制
int hammingWeightV2(uint64_t n) {    n -= (n >> 1) & 0x5555555555555555ULL;    n = ((n >> 2) & 0x3333333333333333ULL) + (n & 0x3333333333333333ULL);    return (((n + (n >> 4)) & 0xF0F0F0F0F0F0F0FULL)            * 0x101010101010101ULL) >> 56;}

这个实现在一些cpu上有问题 type mismatch。不过一般来说和buildin popcnt一样效果

代码语言:javascript代码运行次数:0运行复制
int hammingWeight_popcntV2(uint64_t n) {    int64_t count = 0;    asm("popcnt %1,%0" : "=r"(count) : "rm"(n) : "cc");    return count;}

实现

编译器版本

Dispatch Width

uOps/Cycle

IPC

Block RThroughput

popcnt

gcc 13.2

6

3.67

1.83

1.0

普通实现

gcc 13.2

4

3.94

3.54

2.5

popcnt

clang 17.0.1

6

4.59

2.75

1.0

普通实现

clang 17.0.1

6

4.78

3.83

1.7

popcnt v2

gcc 13.2

6

2.14

2.14

1.3

手写SWAR

gcc 13.2

6

4.09

3.72

3.8

popcnt v2

clang 17.0.1

6

3.67

1.83

1.0

手写SWAR

clang 17.0.1

6

4.09

3.72

3.8

能看出popcnt的Block RThroughput 低,这显然说明性能更好

然后看IPC和uOps/Cycle clang的明显比gcc的要高,但汇编说实话一个两行一个一行,这个没啥比较的意义了

重点和普通实现比,clang生成的汇编要比gcc好一点,Block RThroughput 低 IPC高,且没有特别接近Dispatch Width瓶颈

但说实话就差一个汇编这点差距根本比不出什么。只能大概说一下popcnt的汇编更少,性能更好而已

感觉SWAR这种看起来很屌, 但看mca分析感觉不太行 我跑了个qb压测,但是网站挂了,还需要本地跑一下

https://github.com/wanghenshui/little_bm/blob/dev/hamming_weight/hamming_weight.cc

我的测试结果来看,SWAR性能反而比popcnt要好,即使Block RThroughput 很高,但IPC也很高,性能反而非常好

代码语言:javascript代码运行次数:0运行复制
taskset -c 0  ./hamming_weight2024-02-03T22:39:35+08:00Running ./hamming_weightRun on (16 X 3392.38 MHz CPU s)CPU Caches:  L1 Data 32 KiB (x8)  L1 Instruction 32 KiB (x8)  L2 Unified 512 KiB (x8)  L3 Unified 16384 KiB (x1)Load Average: 0.01, 0.02, 0.00-----------------------------------------------------------------------Benchmark                             Time             CPU   Iterations-----------------------------------------------------------------------BM_hammingWeight_popcnt/0          26.6 ns         26.6 ns     26281110BM_hammingWeight_popcnt/128         265 ns          265 ns      2622989BM_hammingWeight_popcnt/256         526 ns          526 ns      1332695BM_hammingWeight_popcnt/512        1048 ns         1048 ns       666562BM_hammingWeight_popcnt/1024       2096 ns         2095 ns       334434BM_hammingWeight/0                 80.7 ns         80.7 ns      8689750BM_hammingWeight/128               1643 ns         1642 ns       447638BM_hammingWeight/256               3646 ns         3646 ns       195882BM_hammingWeight/512               8099 ns         8097 ns        85508BM_hammingWeight/1024             17193 ns        17190 ns        41208BM_hammingWeightV2/0/0             11.8 ns         11.8 ns     58402778BM_hammingWeightV2/128              118 ns          118 ns      5951445BM_hammingWeightV2/256              233 ns          233 ns      3001257BM_hammingWeightV2/512              463 ns          463 ns      1510925BM_hammingWeightV2/1024             927 ns          927 ns       758631

不过还需要其他机器测试,我的nuc是r9 6950hx zen3+,性能不错

github CI机器,SWAR和popcnt就差不多了。

代码语言:javascript代码运行次数:0运行复制
Running ./bm_hamming_weightRun on (4 X 2868.73 MHz CPU s)CPU Caches:  L1 Data 32 KiB (x2)  L1 Instruction 32 KiB (x2)  L2 Unified 512 KiB (x2)  L3 Unified 32768 KiB (x1)Load Average: 1.98, 0.54, 0.19-----------------------------------------------------------------------Benchmark                             Time             CPU   Iterations-----------------------------------------------------------------------BM_hammingWeight_popcnt/0          17.5 ns         17.5 ns     39446954BM_hammingWeight_popcnt/128         173 ns          173 ns      4056917BM_hammingWeight_popcnt/256         342 ns          342 ns      2051152BM_hammingWeight_popcnt/512         679 ns          679 ns      1032384BM_hammingWeight_popcnt/1024       1354 ns         1354 ns       517551BM_hammingWeight/0                  124 ns          124 ns      5638895BM_hammingWeight/128               2394 ns         2394 ns       280377BM_hammingWeight/256               5511 ns         5511 ns       123293BM_hammingWeight/512              12036 ns        12036 ns        58336BM_hammingWeight/1024             25711 ns        25710 ns        27149BM_hammingWeightV2/0/0             17.8 ns         17.8 ns     39494382BM_hammingWeightV2/128              182 ns          182 ns      3848768BM_hammingWeightV2/256              360 ns          360 ns      1943778BM_hammingWeightV2/512              709 ns          709 ns       988825BM_hammingWeightV2/1024            1418 ns         1418 ns       493319

家人们,需要你们的补充测试,各种机器, 复现代码https://github.com/wanghenshui/little_bm 运行build.sh即可

话说回来,数1到底能干嘛?这里要引入汉明距离 编辑距离相关的概念

简单理解就是查diff 纠错码之类的效果

popcnt的来源 http://www.talkchess.com/forum3/viewtopic.php?t=38521

上个世纪60年代,计算机还属于大型机百花齐放的年代,Control Data Corporation公司的CDC 机器卖的不错,国际象棋也在用这个软件。他们的场景就是棋盘格确认位置,所以实现了popcnt类似的能力,算位置坐标,美国国家安全局(NSA)发现了他们有这个能力,他们的新机器CDC 6000,政府采购并要求加上这个功能,主要是为了类似汉明距离之类的信息统计,相当于变相hash,用来实现校对diff之类的能力,所以也被叫做NSA Instruction (NSA指令)

这个指令也是那个时代的特殊产物把,算力不行并没有高级的hash能力,只能通过数1模拟,后来CPU性能提升渐渐的都不支持了,然后后来部分CPU支持部分CPU不支持,到现代全都捡回来

现在的CPU也有很多不支持popcnt指令,以至于游戏客户端领域会有popcnt patch之类的玩意,给玩家打patch绕过popcnt https://github.com/ogurets/popcnt_emulator

还有什么能用到数1?

指纹?安全领域,这种更多是汉明距离场景的推广

能用到bitmap的地方,不过使用bitmap不一定非得算总数

比如 Hash Array Mapped Tries 结合tries的压缩优点 + bitmap定位槽,

bitmap浪费所以要压缩一下,位运算躲不了数1场景

再比如 Succinct Data Structures terarkdb的memtable用的就这玩意,压缩率高

关于popcnt的信息我就收集到这么多的,大家有其他见解/批评还可以补充一下

另外,跑一下压测代码!看看你的CPU结果是什么样子的

参考• https://vaibhavsagar.com/blog/2019/09/08/popcount/ 一些资料汇总在这里搜到的。我一开始是根据群友聊的和关键字搜到hackernews上这篇文章的分享,介绍了背景和部分应用• https://abseil.io/fast/9 这里说的话我很赞同,性能测试是个周期性的工作,可能旧的代码有时候快,后面时代/硬件进步,又慢了 还是要具体机器具体分析• https://github.com/google/supersonic/blob/master/supersonic/utils/bits.h• https://stackoverflow.com/questions/28802692/how-is-popcnt-implemented-in-hardware 这个没看,但感觉现代CPU popcnt代价已经很低了
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
硬件相关 硬件
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
WPS Office macOS版
WPS Office macOS版

WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,

Shapr3D macOS版
Shapr3D macOS版

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

Adobe After Effects macOS版
Adobe After Effects macOS版

Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

Adobe Audition macOS版
Adobe Audition macOS版

Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

Adobe Bridge macOS版
Adobe Bridge macOS版

Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

Adobe Illustrator macOS版
Adobe Illustrator macOS版

Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

Adobe InDesign macOS版
Adobe InDesign macOS版

Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

Adobe Lightroom Classic macOS版
Adobe Lightroom Classic macOS版

Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

Adobe Media Encoder macOS版
Adobe Media Encoder macOS版

Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

Adobe Photoshop macOS版
Adobe Photoshop macOS版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

WINDOWS 更多
Adobe Photoshop Windows版
Adobe Photoshop Windows版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许

Adobe InDesign Windows版
Adobe InDesign Windows版

Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator

Adobe Illustrator Windows版
Adobe Illustrator Windows版

Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。

Adobe Bridge Windows版
Adobe Bridge Windows版

Adobe Bridge 是 Adobe 推出的创意资产管理工具,可集中预览、分类和查找照片、视频、PDF及多种设计文件,并支持元数据、关键词、评级、批量重命名和格式导出。它可与 Photoshop、Illustrator 等应用衔接,

Affinity Photo Windows版
Affinity Photo Windows版

Affinity Photo 是一款面向摄影师、修图师和视觉设计人员的桌面图像编辑工具,提供 RAW 显影、多图层合成、蒙版、实时滤镜、批处理和色彩管理等功能。原独立产品已停止销售,其照片编辑能力已延续至免费的新 Affinity 应用;

Adobe Lightroom Classic Windows版
Adobe Lightroom Classic Windows版

Adobe Lightroom Classic 是面向 Windows 桌面摄影工作流的照片管理与无损编辑工具,可通过目录集中整理大型图库,并完成 RAW 显影、局部蒙版、批量调整、打印和多格式导出。它强调本地文件管理与精细控制,

Figma Windows版
Figma Windows版

Figma 是面向产品设计与开发团队的云端协作平台,可在 Windows 桌面客户端中完成界面绘制、组件管理、交互原型、评论评审和开发交付。文件保存在云端,多名成员能够同步编辑并共享设计系统;官方同时提供免费 Starter 方案及按席位计

Affinity Designer Windows版
Affinity Designer Windows版

Affinity Designer 是面向矢量图形、数字插画和界面设计的专业创作工具,可在矢量、像素与导出工作区之间快速切换。它提供曲线编辑、形状构建、画板、排版、图层和专业色彩管理,并支持常见设计文件的导入及多种印刷、网页格式输出。

Capture One Pro Windows版
Capture One Pro Windows版

Capture One Pro 是面向摄影师和影像团队的专业桌面照片处理工具,提供相机定制色彩配置、RAW转换、图层与蒙版、联机拍摄、目录及会话管理等功能。它适合棚拍、人像、商业产品、婚礼和风光摄影,

Adobe Acrobat Pro Windows版
Adobe Acrobat Pro Windows版

Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

Adobe After Effects Windows版
Adobe After Effects Windows版

Adobe After Effects 是面向动态图形、动画与影视视觉特效制作的专业工具,可完成关键帧动画、图层合成、遮罩跟踪、抠像、文字动画和二维三维元素整合。Windows 版通过 Adobe Creative Cloud 安装及更新,

DaVinci Resolve Windows版
DaVinci Resolve Windows版

DaVinci Resolve是Blackmagic Design推出的一体化影视后期工具,将素材管理、非线性剪辑、专业调色、Fusion视觉特效、Fairlight音频处理和成片交付整合在统一工程中。免费版已覆盖多数个人创作需求,