gcc -O0 在 2 的幂矩阵大小(矩阵转置)上优于 -O3

2023-12-29

(出于测试目的)我编写了一个简单的方法来计算 nxn 矩阵的转置

void transpose(const size_t _n, double* _A) {
    for(uint i=0; i < _n; ++i) {
        for(uint j=i+1; j < _n; ++j) {
            double tmp  = _A[i*_n+j];
            _A[i*_n+j] = _A[j*_n+i];
            _A[j*_n+i] = tmp;
        }
    }
}

当使用优化级别 O3 或 Ofast 时,我希望编译器展开一些循环,这将带来更高的性能,特别是当矩阵大小是 2 的倍数(即,每次迭代可以执行双循环体)或类似的情况时。相反,我测量的结果恰恰相反。 2 的幂实际上显示执行时间显着增加。

这些尖峰也以 64 为间隔,以 128 为间隔更明显,依此类推。每个尖峰延伸到相邻的矩阵大小,如下表所示

size n  time(us)
1020    2649
1021    2815
1022    3100
1023    5428
1024    15791
1025    6778
1026    3106
1027    2847
1028    2660
1029    3038
1030    2613

我使用 gcc 版本 4.8.2 进行编译,但 clang 3.5 也会发生同样的情况,所以这可能是一些通用的东西?

所以我的问题基本上是:为什么执行时间会周期性增加?它是任何优化选项附带的通用东西吗(就像 clang 和 gcc 一样)?如果是这样,哪个优化选项导致了这种情况?

这怎么会如此重要,以至于该程序的 O0 版本的性能也比 03 版本高出 512 的倍数呢?


EDIT:请注意此(对数)图中尖峰的大小。通过优化转置 1024x1024 矩阵实际上需要与转置 1300x1300 矩阵一样多的时间without优化。如果这是缓存错误/页面错误问题,那么有人需要向我解释为什么程序的优化版本的内存布局如此显着不同,以至于它在 2 的幂上失败,只是为了恢复高性能稍大的矩阵。缓存错误不应该创建更多类似步骤的模式吗?为什么执行时间又下降了? (为什么优化会产生以前不存在的缓存故障?)


EDIT:以下应该是 gcc 生成的汇编代码

没有优化(O0):

_Z9transposemRPd:
.LFB0:
    .cfi_startproc
    push    rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov rbp, rsp
    .cfi_def_cfa_register 6
    mov QWORD PTR [rbp-24], rdi
    mov QWORD PTR [rbp-32], rsi
    mov DWORD PTR [rbp-4], 0
    jmp .L2
.L5:
    mov eax, DWORD PTR [rbp-4]
    add eax, 1
    mov DWORD PTR [rbp-8], eax
    jmp .L3
.L4:
    mov rax, QWORD PTR [rbp-32]
    mov rdx, QWORD PTR [rax]
    mov eax, DWORD PTR [rbp-4]
    imul    rax, QWORD PTR [rbp-24]
    mov rcx, rax
    mov eax, DWORD PTR [rbp-8]
    add rax, rcx
    sal rax, 3
    add rax, rdx
    mov rax, QWORD PTR [rax]
    mov QWORD PTR [rbp-16], rax
    mov rax, QWORD PTR [rbp-32]
    mov rdx, QWORD PTR [rax]
    mov eax, DWORD PTR [rbp-4]
    imul    rax, QWORD PTR [rbp-24]
    mov rcx, rax
    mov eax, DWORD PTR [rbp-8]
    add rax, rcx
    sal rax, 3
    add rdx, rax
    mov rax, QWORD PTR [rbp-32]
    mov rcx, QWORD PTR [rax]
    mov eax, DWORD PTR [rbp-8]
    imul    rax, QWORD PTR [rbp-24]
    mov rsi, rax
    mov eax, DWORD PTR [rbp-4]
    add rax, rsi
    sal rax, 3
    add rax, rcx
    mov rax, QWORD PTR [rax]
    mov QWORD PTR [rdx], rax
    mov rax, QWORD PTR [rbp-32]
    mov rdx, QWORD PTR [rax]
    mov eax, DWORD PTR [rbp-8]
    imul    rax, QWORD PTR [rbp-24]
    mov rcx, rax
    mov eax, DWORD PTR [rbp-4]
    add rax, rcx
    sal rax, 3
    add rdx, rax
    mov rax, QWORD PTR [rbp-16]
    mov QWORD PTR [rdx], rax
    add DWORD PTR [rbp-8], 1
.L3:
    mov eax, DWORD PTR [rbp-8]
    cmp rax, QWORD PTR [rbp-24]
    jb  .L4
    add DWORD PTR [rbp-4], 1
.L2:
    mov eax, DWORD PTR [rbp-4]
    cmp rax, QWORD PTR [rbp-24]
    jb  .L5
    pop rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   _Z9transposemRPd, .-_Z9transposemRPd
    .ident  "GCC: (Debian 4.8.2-15) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

优化 (O3)

_Z9transposemRPd:
.LFB0:
    .cfi_startproc
    push    rbx
    .cfi_def_cfa_offset 16
    .cfi_offset 3, -16
    xor r11d, r11d
    xor ebx, ebx
.L2:
    cmp r11, rdi
    mov r9, r11
    jae .L10
    .p2align 4,,10
    .p2align 3
.L7:
    add ebx, 1
    mov r11d, ebx
    cmp rdi, r11
    mov rax, r11
    jbe .L2
    mov r10, r9
    mov r8, QWORD PTR [rsi]
    mov edx, ebx
    imul    r10, rdi
    .p2align 4,,10
    .p2align 3
.L6:
    lea rcx, [rax+r10]
    add edx, 1
    imul    rax, rdi
    lea rcx, [r8+rcx*8]
    movsd   xmm0, QWORD PTR [rcx]
    add rax, r9
    lea rax, [r8+rax*8]
    movsd   xmm1, QWORD PTR [rax]
    movsd   QWORD PTR [rcx], xmm1
    movsd   QWORD PTR [rax], xmm0
    mov eax, edx
    cmp rdi, rax
    ja  .L6
    cmp r11, rdi
    mov r9, r11
    jb  .L7
.L10:
    pop rbx
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE0:
    .size   _Z9transposemRPd, .-_Z9transposemRPd
    .ident  "GCC: (Debian 4.8.2-15) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

执行时间的周期性增加一定是由于缓存只是N路关联而不是全关联造成的。您正在目睹与缓存行选择算法相关的哈希冲突。

最快的 L1 缓存的缓存行数比下一级 L2 少。在每个级别中,每个缓存行只能从一组有限的源中填充。

高速缓存行选择算法的典型硬件实现将仅使用内存地址中的少数位来确定数据应写入哪个高速缓存槽中——在硬件中,移位是自由的。

这会导致内存范围之间的竞争,例如地址 0x300010 和 0x341010 之间。 在完全顺序算法中,这并不重要——N足够大,实际上可以all形式的算法:

 for (i=0;i<1000;i++) a[i] += b[i] * c[i] + d[i];

但是,当输入(或输出)数量变大时(算法优化时会在内部发生这种情况),缓存中的一个输入会强制将另一个输入移出缓存。

 // one possible method of optimization with 2 outputs and 6 inputs
 // with two unrelated execution paths -- should be faster, but maybe it isn't
 for (i=0;i<500;i++) { 
       a[i]     += b[i]     * c[i]     + d[i];
       a[i+500] += b[i+500] * c[i+500] + d[i+500];
 }

中的一个图表示例 5:缓存关联性 http://igoro.com/archive/gallery-of-processor-cache-effects/说明了矩阵行之间的 512 字节偏移是特定系统的全局最坏情况尺寸。当知道这一点时,有效的缓解措施是将矩阵水平过度分配到某个其他维度char matrix[512][512 + 64].

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gcc -O0 在 2 的幂矩阵大小(矩阵转置)上优于 -O3 的相关文章

  • MVC 重定向到没有控制器的视图

    希望应该是一个简单的 我创建了一个通用错误视图 当整个站点的操作方法内发生异常时 我想显示该视图 我创建了一个部分页面 所有导航都位于其中 因此我不需要在此视图上使用控制器 那么如何从控制器内的操作方法重定向到它 像这样的东西 HttpPo
  • 没有 Unicode 字节顺序标记。无法切换到 Unicode

    我正在使用 XSD 编写 XML 验证器 下面是我所做的 但是当验证器到达该线时while list Read 它给了我错误 没有 Unicode 字节顺序标记 无法切换到 Unicode 有人可以帮我解决吗 public class Va
  • 检查列表是否包含另一个列表。 C#

    编辑 只是说 ContainsAllItem 中的注释解释得最好 很抱歉问这个问题 我知道以前有人问过这个问题 但我只是不明白 好的 所以我想检查一个列表是否包含另一个列表中的所有项目WITHOUT重叠 以及根据类字符串 名称变量 称为项目
  • 使用不带参数的 Split() 时,默认分隔符是什么?

    所以我看了看String Split 今天 C 中的方法 我意识到你也可以向它传递零参数 这是我从未考虑过的 使用时默认的分隔符是什么Split 没有任何参数 如果没有值 则为空白 来源自here https msdn microsoft
  • 如何将pdf页面设置设置为打印属性对话框?

    大家好 我想知道如何设置 pdf 页面设置到打印属性对话框 例如 如果我的 PDF 页面设置为横向 则布局会自动显示横向而不是纵向 如果我的 PDF 页面设置为纵向 则布局会自动显示纵向 我在这个主题上做了很多研发 但没有找到任何满意的链接
  • 返回 int& 的函数[重复]

    这个问题在这里已经有答案了 我在网上查了一下发现一篇试图解释的文章std move和右值 http thbecker net articles rvalue references section 01 html并发现了一些我实在无法掌握的东
  • 通过引用传递时取消引用指针

    当通过引用传递给函数时取消引用指针时会发生什么 这是一个简单的例子 int returnSame int example return example int main int inum 3 int pinum inum std cout
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 用 C# 制作 Vista 风格的应用程序

    我正在运行 Windows Vista 并且希望外观看起来像常规 Vista 程序 有没有关于如何构建 Vista 风格应用程序的真正好的教程 文章 我还想学习如何使用本机代码并将其转换为 C 如this http bartdesmet n
  • 导出到 CSV 时 Gridview 出现空行

    这个问题是由进一步讨论引发的这个问题 https stackoverflow com questions 6674555 export gridview data into csv file 6674589 noredirect 1 com
  • 抽象类或接口。哪种方式是正确的?

    有两种方法可以选择抽象类或接口 微软解决方案和Oracle解决方案 微软 设计指南 请使用抽象 在 Visual Basic 中为 MustInherit 类而不是接口来将协定与实现分离 http msdn microsoft com en
  • 指示泛型返回动态类型的对象

    这个问题是我原来问题的后续问题here https stackoverflow com questions 2541184 using a type object to create a generic 假设我有以下泛型类 简化 class
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 从包含大量文件的目录中检索文件

    我的目录包含近 14 000 000 个 wav 格式的音频样本 所有普通存储 没有子目录 我想循环浏览文件 但是当我使用DirectoryInfo GetFiles 在该文件夹上 整个应用程序冻结了几分钟 可以用另一种方式完成吗 也许读取
  • 如何将字符串转换为 Indian Money 格式?

    我正在尝试将字符串转换为印度货币格式 例如如果输入为 1234567 则输出应为 12 34 567 我编写了以下代码 但它没有给出预期的输出 CultureInfo hindi new CultureInfo hi IN string t
  • 理解 C++11 中的 std::atomic::compare_exchange_weak()

    bool compare exchange weak T expected T val compare exchange weak 是 C 11 中提供的比较交换原语之一 它是weak即使对象的值等于 它也会返回 falseexpected
  • Dynamics Crm:获取状态代码/状态代码映射的元数据

    在 Dynamics CRM 2011 中 在事件实体上 状态原因 选项集 也称为状态代码 与 状态 选项集 也称为状态代码 相关 例如看这个截图 当我使用 API 检索状态原因选项集时 如下所示 RetrieveAttributeRequ
  • 微软语音识别速度

    我正在使用微软的语音识别器开发一个小型练习应用程序 对于我正在做的事情来说 我似乎无法让它足够快地识别单个单词 我希望能够正常说话 系统将从我所说的内容中抓取 关键字 并生成一个字符串 目前我正在使用 5 个单词的自定义语法 红 蓝 黄 绿
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use

随机推荐

  • Express GET 路由不适用于参数

    我是 Express 和 Mongoose 的新手 我目前正在开发我的第一个项目 这不是教程 我遇到了问题 我有多个路由 它们在 index js 中定义如下 app use api client require routes client
  • 如何从字符串中读取 NSDate?

    我有带有日期的字符串 并且想将它们解析为 NSDate 对象 有没有办法做到这一点 我看过 NSDate 和 NSScanner 但没有看到任何可以从字符串中读取它的东西 在cocoa sdk中 通常是 如果您想要一个日期并且有一个字符串
  • MVC 场景中的 Javascript 事件与回调

    我正在尝试找出一种很好的方法来拥有视图和控制器并最大限度地减少它们之间的联系 除了一个事件有多个订阅者之外 像这样的 js 代码之间还有什么主要区别吗 var customers get function callback get cust
  • 使用循环时如何使 makefile 错误退出?

    如果我有以下 bash 命令 for i in x do ls i done echo OK 执行 ls 然后执行 ls x 失败 缺少 x 并且不打印 OK If for i in x do ls i done echo OK 那么即使
  • Google Cloud Platform:从命令行登录 GCP

    我确信这会很简单 但找不到任何文档或解决方案 我正在尝试使用 gcloud 编写一个脚本来在我的 GCP 实例中执行一些操作 是否可以仅通过命令行使用 gcloud 登录 身份验证 Thanks 这里有几个选择 取决于您到底想做什么 第一个
  • 原则 2 - 从实体外部禁用 PrePersist

    我正在尝试从 Doctrine 2 中的实体外部禁用实体事件 每次我们将新记录插入表中时 都需要运行很少的文件操作 这些操作已在带有 prePersist 注释的方法中实现 但是 我还需要运行一些数据装置并跳过文件操作部分作为测试的一部分
  • 强制轨迹栏值为十倍

    我用 C 在 Winform 项目上添加了一个轨迹栏 mySlider Minimum 0 mySlider Maximum 200 mySlider Value 30 mySlider SmallChange 10 mySlider La
  • Java applet 清单 - 允许所有 Caller-Allowable-Codebase

    从 Java 7u45 开始 如果网页尝试通过 javascript 与小程序交互 并且该页面未在清单的 Caller Allowable Codebase 属性中列出 则小程序将显示警告消息 即使使用受信任的证书进行签名 有关此更改的发行
  • 是否抛出 ConcurrentModificationException 取决于系统

    我正在使用 Iterator 编写一段代码 当我在 Windows 上从 IDE 运行该程序时 在 a 行收到 ConcurrentModificationException LinkedList ll new LinkedList Ite
  • 是否应该在编写代码之前先编写单元测试?

    我知道测试驱动开发的定义原则之一是首先编写单元测试 然后编写代码来通过这些单元测试 但是有必要这样做吗 我发现 在编写之前 我常常不知道自己在测试什么 主要是因为我过去从事的几个项目更多地是从概念验证演变而来 而不是设计出来的 我之前曾尝试
  • UNIQUE 约束失败

    我正在使用 Django 进行 Tango 但无法解决这个练习 我明白了django db utils IntegrityError UNIQUE constraint failed rango category name错误 这是我尝试实
  • IE 浏览器控件 res:// 用法

    我在我的应用程序中使用 IWebBrowser2 控件 并且有各种 html 文件作为资源存储在 exe 中 为了加载这些 我使用 res 协议 问题是 对于某些版本的 IE 页面不再加载 而只是显示 操作已取消 Internet Expl
  • 如何根据另一个矩阵、data.frame 或向量的行重新排序

    test1 lt as matrix c 1 2 3 4 5 row names test1 lt c a d c b e test2 lt as matrix c 6 7 8 9 10 row names test2 lt c e d c
  • 为我的 numpy 数组提供更紧凑的 __repr__ 吗?

    当我显示数组时 默认 repr 方法用于ndarray对象对于我想做的事情来说太大了 a np eye 32 b hello 42 array a b 产生 array array 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1
  • MongoDB 选择 _id 数组中的哪个位置?

    在 mongo db 中可以像 SQL 一样选择集合的文档 SELECT FROM collection WHERE id IN 1 2 3 4 或者如果我有一个 id array我必须一一选择 然后重新组合array object结果 E
  • 从命令行启动进程时如何捕获进程的 PID?

    有没有办法纯粹在 bat 文件中执行此操作 目的是推出iexplore exe 然后在完成时杀死该实例 这是我使用的 echo off rem there is a tab in the file at the end of the lin
  • 注释声明中 String[] 的默认“”是什么?

    什么是default 下面代码中的部分是什么意思 public interface MyAnnotation String names default 是否等于 String names default new String 0 publi
  • 将响应发送给除发件人之外的所有客户端

    要将某些内容发送给所有客户 您可以使用 io sockets emit response data 要接收来自客户的信息 您可以使用 socket on cursor function data 如何将两者结合起来 以便在服务器上从客户端接
  • enctype“application/json”形式可用吗?

    我正在读这个w3c 文档 https www w3 org TR html json forms 关于用 html 表单发布 JSON 数据 并尝试测试它 我的测试表格如下
  • gcc -O0 在 2 的幂矩阵大小(矩阵转置)上优于 -O3

    出于测试目的 我编写了一个简单的方法来计算 nxn 矩阵的转置 void transpose const size t n double A for uint i 0 i lt n i for uint j i 1 j lt n j dou