为什么 VS C++ 2017 编译器仅在迭代指针未存储在结构中时才使用 SSE 优化?

如何解决为什么 VS C++ 2017 编译器仅在迭代指针未存储在结构中时才使用 SSE 优化?

动机很简单:我遍历两个 uint64 数组、位元和它们的值,并将结果存储在第三个数组中。然而,在我概括了以结构形式接受输入的解决方案后,代码速度大大减慢,我发现生成的程序集相当不同。我的问题是为什么会这样,我该如何防止这种行为? (有关动机的更多详细信息,请参阅问题末尾的注释。)

最小化后的代码如下所示:

struct FAndExpressionIter
{
public:
    const uint64* LhsIter = nullptr;
    const uint64* RhsIter = nullptr;

    inline void operator++()
    {
        ++LhsIter;
        ++RhsIter;
    }

    inline uint64 operator*() const
    {
        return (*LhsIter & *RhsIter);
    }
};


void FooBitAndExpression(FAndExpressionIter SrcIter,uint64* ResultIter,const uint64* ResultEnd)
{
    while (ResultIter != ResultEnd)
    {
        *ResultIter = *SrcIter;
        ++SrcIter;
        ++ResultIter;
    }
}

void FooBitAndRaw(const uint64* LhsIter,const uint64* RhsIter,const uint64* ResultEnd)
{
    while (ResultIter != ResultEnd)
    {
        *ResultIter = (*LhsIter & *RhsIter);
        ++LhsIter;
        ++RhsIter;
        ++ResultIter;
    }
}

FooBitAndExpression 被编译成:

00007FFA37075910  mov         qword ptr [rsp+8],rbx  
     7:     while (ResultIter != ResultEnd)
00007FFA37075915  xor         r10d,r10d  
00007FFA37075918  mov         rbx,r8  
00007FFA3707591B  sub         rbx,rdx  
00007FFA3707591E  mov         r9,rdx  
00007FFA37075921  add         rbx,7  
00007FFA37075925  mov         r11,rcx  
00007FFA37075928  shr         rbx,3  
00007FFA3707592C  cmp         rdx,r8  
00007FFA3707592F  cmova       rbx,r10  
00007FFA37075933  test        rbx,rbx  
00007FFA37075936  je          FooBitAndExpression+55h (07FFA37075965h)  
00007FFA37075938  mov         rax,qword ptr [rcx+8]  
00007FFA3707593C  nop         dword ptr [rax]  
     8:     {
     9:         *ResultIter = *SrcIter;
00007FFA37075940  mov         rdx,qword ptr [r11]  
    10:         ++SrcIter;
00007FFA37075943  lea         rax,[rax+8]  
    11:         ++ResultIter;
00007FFA37075947  inc         r10  
00007FFA3707594A  lea         r9,[r9+8]  
     8:     {
     9:         *ResultIter = *SrcIter;
00007FFA3707594E  mov         rcx,qword ptr [rdx]  
00007FFA37075951  and         rcx,qword ptr [rax-8]  
00007FFA37075955  mov         qword ptr [r9-8],rcx  
    10:         ++SrcIter;
00007FFA37075959  lea         rcx,[rdx+8]  
00007FFA3707595D  mov         qword ptr [r11],rcx  
     7:     while (ResultIter != ResultEnd)
00007FFA37075960  cmp         r10,rbx  
00007FFA37075963  jne         FooBitAndExpression+30h (07FFA37075940h)  
    12:     }
    13: }
00007FFA37075965  mov         rbx,qword ptr [rsp+8]  
    12:     }
    13: }
00007FFA3707596A  ret  

FooBitAndRaw 被编译为:

    17:     while (ResultIter != ResultEnd)
00007FFA37075980  xor         r10d,r10d  
00007FFA37075983  mov         r11,r9  
00007FFA37075986  sub         r11,r8  
00007FFA37075989  add         r11,7  
00007FFA3707598D  shr         r11,3  
00007FFA37075991  cmp         r8,r9  
00007FFA37075994  cmova       r11,r10  
00007FFA37075998  test        r11,r11  
00007FFA3707599B  je          FooBitAndRaw+0F7h (07FFA37075A77h)  
00007FFA370759A1  cmp         r11,8  
00007FFA370759A5  jb          FooBitAndRaw+0D2h (07FFA37075A52h)  
00007FFA370759AB  lea         rax,[rdx-8]  
00007FFA370759AF  lea         rax,[rax+r11*8]  
00007FFA370759B3  lea         r9,[r8-8]  
00007FFA370759B7  lea         r9,[r9+r11*8]  
00007FFA370759BB  cmp         r8,rax  
00007FFA370759BE  ja          FooBitAndRaw+49h (07FFA370759C9h)  
00007FFA370759C0  cmp         r9,rdx  
00007FFA370759C3  jae         FooBitAndRaw+0D2h (07FFA37075A52h)  
00007FFA370759C9  lea         rax,[rcx-8]  
00007FFA370759CD  lea         rax,[rax+r11*8]  
00007FFA370759D1  cmp         r8,rax  
00007FFA370759D4  ja          FooBitAndRaw+5Bh (07FFA370759DBh)  
00007FFA370759D6  cmp         r9,rcx  
00007FFA370759D9  jae         FooBitAndRaw+0D2h (07FFA37075A52h)  
00007FFA370759DB  mov         rax,r11  
00007FFA370759DE  and         rax,0FFFFFFFFFFFFFFF8h  
00007FFA370759E2  nop         dword ptr [rax]  
00007FFA370759E6  nop         word ptr [rax+rax]  
    18:     {
    19:         *ResultIter = (*LhsIter & *RhsIter);
00007FFA370759F0  movdqu      xmm0,xmmword ptr [rdx]  
    20:         ++LhsIter;
    21:         ++RhsIter;
    22:         ++ResultIter;
00007FFA370759F4  add         r10,8  
00007FFA370759F8  movdqu      xmm1,xmmword ptr [rcx]  
00007FFA370759FC  pand        xmm1,xmm0  
00007FFA37075A00  movdqu      xmm0,xmmword ptr [rdx+10h]  
00007FFA37075A05  movdqu      xmmword ptr [r8],xmm1  
00007FFA37075A0A  movdqu      xmm1,xmmword ptr [rcx+10h]  
00007FFA37075A0F  pand        xmm1,xmm0  
00007FFA37075A13  movdqu      xmm0,xmmword ptr [rdx+20h]  
00007FFA37075A18  movdqu      xmmword ptr [r8+10h],xmm1  
00007FFA37075A1E  movdqu      xmm1,xmmword ptr [rcx+20h]  
00007FFA37075A23  pand        xmm1,xmm0  
00007FFA37075A27  movdqu      xmm0,xmmword ptr [rdx+30h]  
00007FFA37075A2C  add         rdx,40h  
00007FFA37075A30  movdqu      xmmword ptr [r8+20h],xmm1  
00007FFA37075A36  movdqu      xmm1,xmmword ptr [rcx+30h]  
00007FFA37075A3B  add         rcx,40h  
00007FFA37075A3F  pand        xmm1,xmm0  
00007FFA37075A43  movdqu      xmmword ptr [r8+30h],xmm1  
00007FFA37075A49  add         r8,40h  
00007FFA37075A4D  cmp         r10,rax  
00007FFA37075A50  jne         FooBitAndRaw+70h (07FFA370759F0h)  
    17:     while (ResultIter != ResultEnd)
00007FFA37075A52  cmp         r10,r11  
00007FFA37075A55  je          FooBitAndRaw+0F7h (07FFA37075A77h)  
00007FFA37075A57  sub         rcx,rdx  
    17:     while (ResultIter != ResultEnd)
00007FFA37075A5A  sub         r8,rdx  
00007FFA37075A5D  nop         dword ptr [rax]  
    18:     {
    19:         *ResultIter = (*LhsIter & *RhsIter);
00007FFA37075A60  mov         rax,qword ptr [rcx+rdx]  
    20:         ++LhsIter;
    21:         ++RhsIter;
    22:         ++ResultIter;
00007FFA37075A64  inc         r10  
00007FFA37075A67  and         rax,qword ptr [rdx]  
00007FFA37075A6A  mov         qword ptr [r8+rdx],rax  
00007FFA37075A6E  lea         rdx,[rdx+8]  
00007FFA37075A72  cmp         r10,r11  
00007FFA37075A75  jne         FooBitAndRaw+0E0h (07FFA37075A60h)  
    23:     }
    24: }
00007FFA37075A77  ret  

请注意,我对汇编程序的了解非常有限,我的结论是基于猜测。如果我正确理解生成的程序集,FooBitAndRaw 函数将使用 sse 指令循环遍历迭代数据。当剩余空间太小时,回退到单值迭代。

然而,FooBitAndExpression 函数没有做这样的事情并且立即迭代单个值。据我了解,除了两个内联的方法调用外,这两种实现在高级指令中是相同的。

already found out,C# 的 JIT 不会在用于迭代的局部结构变量中使用变量寄存器,这会大大降低应用程序的速度。显然,MS Visual C++ 在类似情况下使用寄存器,但它让我想到了一个子问题:如果变量存储在本地结构中,是否有类似的限制不允许使用 sse 优化?

更多细节和注意事项:

  • 我相信这不是过早的优化。最初,我只是将布尔值存储为完全不同结构的成员变量,并在我想对这些字段运行逻辑运算时简单地迭代这些结构的数组。它被指定用于一定数量的元素。然而,输入增加幅度和代码非常缓慢。所以作为优化,我实现了基于位域的结构来存储某些布尔值。我工作的大部分系统都是 O(N),但是使用这些位域技巧的部分是 O(M*N),因此即使是微小的变化也会显着影响性能。
  • 当我尝试通过展开循环来优化实现时,我注意到了这种行为。 FooBitAndExpression 速度更快,而 FooBitAndRaw 速度明显减慢,这是出乎意料的,因此我进行了调查 - 并发现了这一点。
  • 我的主要动机/目标是什么:在分析之后,我发现了代码中最薄弱的部分并对其进行了优化(例如通过实现 FooBitAndRaw)。但是,代码变得不那么可读了,所以现在我想在不影响性能的情况下返回一些可读性。我打算将一些源数据和操作封装在结构中。目前,使用优化位操作的代码必须在每行代码中进行注释以描述意图,因为从需要 6 个以上参数的函数调用中看不清楚。
  • 这只是一个例子。我还为逻辑或异或,某些类型的比较等实现了类似的功能。这就是我实现 FooBitAndExpression 功能的原因。下一步是将其更改为模板以支持各种输入表达式。
  • 我在 Windows 10 上使用 Visual Studio C++ 2017。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res