搜索
首页后端开发C++为什么将循环计数器从'unsigned”更改为'uint64_t”会显着影响 x86 CPU 上'_mm_popcnt_u64”的性能,以及编译器优化和变量声明如何影响

Why does changing a loop counter from `unsigned` to `uint64_t` significantly impact the performance of `_mm_popcnt_u64` on x86 CPUs, and how does compiler optimization and variable declaration affect this performance difference?

探究 u64 循环计数器与 x86 CPUs 上的 _mm_popcnt_u64 不同寻常的性能差异

简介

我在寻找快速对大型数据数组进行 popcount 的方法时,遇到了一个非常奇怪的现象:将循环变量从 unsigned 更改为 uint64_t 使我的 PC 上的性能下降了 50%。

基准测试

#include <iostream>
#include <chrono>
#include <x86intrin.h>

int main(int argc, char* argv[]) {

    using namespace std;
    if (argc != 2) {
       cerr (buffer);
    for (unsigned i=0; i<size charbuffer rand uint64_t count chrono::time_point> startP,endP;
    {
        startP = chrono::system_clock::now();
        count = 0;
        for( unsigned k = 0; k (endP-startP).count();
        cout (endP-startP).count();
        cout <p>如您所见,我们创建了一个大小为 x MB 的随机数据缓冲区,其中 x 从命令行读取。然后,我们迭代缓冲区并使用 x86 popcount 内联函数的一个展开版本执行 popcount。为了获得更精确的结果,我们执行 10,000 次 popcount。我们测量 popcount 的时间。在第一种情况下,内部循环变量未签名,在第二种情况下,内部循环变量为 uint64_t。我认为这不应该有任何区别,但事实并非如此。</p>
<p><strong>(绝对疯狂的)结果</strong></p>
<p>我这样编译它(g   版本:Ubuntu 4.8.2-19ubuntu1):</p>
<pre class="brush:php;toolbar:false">g++ -O3 -march=native -std=c++11 test.cpp -o test

这是我在我的 Haswell Core i7-4770K CPU @ 3.50GHz 上运行测试 1(所以 1MB 随机数据)的结果:

  • unsigned 41959360000 0.401554 秒 26.113 GB/秒
  • uint64_t 41959360000 0.759822 秒 13.8003 GB/秒

如您所见,uint64_t 版本的吞吐量只有 unsigned 版本的一半!该问题似乎是生成了不同的汇编,但原因是什么?首先,我认为这是一个编译器错误,所以我尝试了 clang (Ubuntu Clang 版本 3.4-1ubuntu3):

clang++ -O3 -march=native -std=c++11 teest.cpp -o test

测试结果 1:

  • unsigned 41959360000 0.398293 秒 26.3267 GB/秒
  • uint64_t 41959360000 0.680954 秒 15.3986 GB/秒

因此,几乎得到了相同的结果,仍然很奇怪。但现在变得非常奇怪。我将从输入中读取的缓冲区大小替换为常量 1,所以我在:

uint64_t size = atol(argv[1]) <p>改为:</p><pre class="brush:php;toolbar:false">uint64_t size = 1 <p>因此,编译器现在知道编译时的缓冲区大小。也许它可以添加一些优化!以下是在 g   中的数字:</p>
  • unsigned 41959360000 0.509156 秒 20.5944 GB/秒
  • uint64_t 41959360000 0.508673 秒 20.6139 GB/秒

现在,两个版本的速度都一样快。然而,与 unsigned 相比, velocidade 甚至变得更慢了!它从 26 GB/秒下降到 20 GB/秒,因此用一个常量值替换一个非常规常量导致 去优化。严重的是,我在此处毫无头绪!但现在用 clang 和新版本:

uint64_t size = atol(argv[1]) <p>改为:</p><pre class="brush:php;toolbar:false">uint64_t size = 1 <p>结果:</p>
  • unsigned 41959360000 0.677009 sec 15.4884 GB/s
  • uint64_t 41959360000 0.676909 sec 15.4906 GB/s

等等,发生了什么事?现在,两个版本都下降到了 15GB/s 的 速度。因此,用一个常量值替换一个非常规常量值甚至导致了 个版本的代码速度变慢对于 Clang!

我请一位使用 Ivy Bridge CPU 的同事编译我的基准测试。他得到了类似的结果,所以这似乎不是 Haswell 独有。由于有两个编译器在此处产生奇怪的结果,因此这似乎也不是编译器错误。由于我们这里没有 AMD CPU,所以我们只能使用 Intel 进行测试。

更多疯狂,拜托!

使用第一个示例(带有 atol(argv[1]) 的示例),在变量前面放置一个 static,即:

#include <iostream>
#include <chrono>
#include <x86intrin.h>

int main(int argc, char* argv[]) {

    using namespace std;
    if (argc != 2) {
       cerr (buffer);
    for (unsigned i=0; i<size charbuffer rand uint64_t count chrono::time_point> startP,endP;
    {
        startP = chrono::system_clock::now();
        count = 0;
        for( unsigned k = 0; k (endP-startP).count();
        cout (endP-startP).count();
        cout <p>以下是她在 g   中的结果:</p>
<ul>
<li>unsigned 41959360000 0.396728 秒 26.4306 GB/秒</li>
<li>uint64_t 41959360000 0.509484 秒 20.5811 GB/秒</li>
</ul>
<p>耶,还有另一个替代方案!我们仍然拥有 32GB/s 与 u3,但我们设法将 u64 至少从 13GB/s 版本提升到 20GB/s 版本!在我的同事的电脑上,u64 版本甚至比 u32 版本更快,获得了最好的结果。遗憾的是,这仅适用于 g  ,clang   似乎不在乎 static。</p>
<p>**我的问题</p></size></x86intrin.h></chrono></iostream>

以上是为什么将循环计数器从'unsigned”更改为'uint64_t”会显着影响 x86 CPU 上'_mm_popcnt_u64”的性能,以及编译器优化和变量声明如何影响的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
C#vs. C:编程语言的比较分析C#vs. C:编程语言的比较分析May 04, 2025 am 12:03 AM

C#和C 的主要区别在于语法、内存管理和性能:1)C#语法现代,支持lambda和LINQ,C 保留C特性并支持模板。2)C#自动内存管理,C 需要手动管理。3)C 性能优于C#,但C#性能也在优化中。

用C构建XML应用程序:实例用C构建XML应用程序:实例May 03, 2025 am 12:16 AM

在C 中处理XML数据可以使用TinyXML、Pugixml或libxml2库。1)解析XML文件:使用DOM或SAX方法,DOM适合小文件,SAX适合大文件。2)生成XML文件:将数据结构转换为XML格式并写入文件。通过这些步骤,可以有效地管理和操作XML数据。

C中的XML:处理复杂的数据结构C中的XML:处理复杂的数据结构May 02, 2025 am 12:04 AM

在C 中处理XML数据结构可以使用TinyXML或pugixml库。1)使用pugixml库解析和生成XML文件。2)处理复杂的嵌套XML元素,如书籍信息。3)优化XML处理代码,建议使用高效库和流式解析。通过这些步骤,可以高效处理XML数据。

C和性能:它仍然主导C和性能:它仍然主导May 01, 2025 am 12:14 AM

C 在性能优化方面仍然占据主导地位,因为其低级内存管理和高效执行能力使其在游戏开发、金融交易系统和嵌入式系统中不可或缺。具体表现为:1)在游戏开发中,C 的低级内存管理和高效执行能力使得它成为游戏引擎开发的首选语言;2)在金融交易系统中,C 的性能优势确保了极低的延迟和高吞吐量;3)在嵌入式系统中,C 的低级内存管理和高效执行能力使得它在资源有限的环境中非常受欢迎。

C XML框架:为您选择合适的一个C XML框架:为您选择合适的一个Apr 30, 2025 am 12:01 AM

C XML框架的选择应基于项目需求。1)TinyXML适合资源受限环境,2)pugixml适用于高性能需求,3)Xerces-C 支持复杂的XMLSchema验证,选择时需考虑性能、易用性和许可证。

C#vs. C:为您的项目选择正确的语言C#vs. C:为您的项目选择正确的语言Apr 29, 2025 am 12:51 AM

C#适合需要开发效率和类型安全的项目,而C 适合需要高性能和硬件控制的项目。 1)C#提供垃圾回收和LINQ,适用于企业应用和Windows开发。 2)C 以高性能和底层控制着称,广泛用于游戏和系统编程。

c  怎么进行代码优化c 怎么进行代码优化Apr 28, 2025 pm 10:27 PM

C 代码优化可以通过以下策略实现:1.手动管理内存以优化使用;2.编写符合编译器优化规则的代码;3.选择合适的算法和数据结构;4.使用内联函数减少调用开销;5.应用模板元编程在编译时优化;6.避免不必要的拷贝,使用移动语义和引用参数;7.正确使用const帮助编译器优化;8.选择合适的数据结构,如std::vector。

如何理解C  中的volatile关键字?如何理解C 中的volatile关键字?Apr 28, 2025 pm 10:24 PM

C 中的volatile关键字用于告知编译器变量值可能在代码控制之外被改变,因此不能对其进行优化。1)它常用于读取可能被硬件或中断服务程序修改的变量,如传感器状态。2)volatile不能保证多线程安全,应使用互斥锁或原子操作。3)使用volatile可能导致性能slight下降,但确保程序正确性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版