调试 Arm neon 代码中的数据/neon 性能危害

2023-12-12

最初,当我尝试时出现了问题优化算法根据 Profiler 的数据,Neon Arm 和其中的一小部分占据了 80%。我尝试测试看看可以采取哪些措施来改进它,为此我创建了指向优化函数的不同版本的函数指针数组,然后在循环中运行它们以在探查器中查看哪个性能更好:

typedef unsigned(*CalcMaxFunc)(const uint16_t a[8][4], const uint16_t b[4][4]);
CalcMaxFunc CalcMaxFuncs[] =
{
    CalcMaxFunc_NEON_0,
    CalcMaxFunc_NEON_1,
    CalcMaxFunc_NEON_2,
    CalcMaxFunc_NEON_3,
    CalcMaxFunc_C_0
};


int N = sizeof(CalcMaxFunc) / sizeof(CalcMaxFunc[0]);
for (int i = 0; i < 10 * N; ++i)
{
    auto f = CalcMaxFunc[i % N];
    unsigned retI = f(a, b);

    // just random code to ensure that cpu waits for the results
    // and compiler doesn't optimize it away
    if (retI > 1000000)
        break;
    ret |= retI;
}

我得到了令人惊讶的结果:函数的性能完全取决于它在 CalcMaxFuncs 数组中的位置。例如,当我将 CalcMaxFunc_NEON_3 交换为第一个时,它会慢 3-4 倍,并且根据分析器,它会在函数的最后一位尝试将数据从 neon 移动到 Arm 寄存器时停止。

那么,是什么导致它有时会造成停顿,而有时却不会呢?顺便说一句,如果重要的话,我会在 xcode 中对 iPhone6 进行配置。

当我通过在循环中调用这些函数之间混合一些浮点除法来故意引入 neon 管道停顿时,我消除了不可靠的行为,现在无论调用它们的顺序如何,它们都执行相同的操作。那么,为什么我首先会遇到这个问题,我该如何在实际代码中消除它呢?

Update:我尝试创建一个简单的测试函数,然后分阶段优化它,看看如何避免 neon->arm 失速。 这是测试运行器功能:

void NeonStallTest()
{
    int findMinErr(uint8_t* var1, uint8_t* var2, int size);
    srand(0);
    uint8_t var1[1280];
    uint8_t var2[1280];
    for (int i = 0; i < sizeof(var1); ++i)
    {
        var1[i] = rand();
        var2[i] = rand();
    }
#if 0 // early exit?
    for (int i = 0; i < 16; ++i)
        var1[i] = var2[i];
#endif
    int ret = 0;
    for (int i=0; i<10000000; ++i)
        ret += findMinErr(var1, var2, sizeof(var1));
    exit(ret);
}

And findMinErr这是:

int findMinErr(uint8_t* var1, uint8_t* var2, int size)
{
    int ret = 0;
    int ret_err = INT_MAX;
    for (int i = 0; i < size / 16; ++i, var1 += 16, var2 += 16)
    {
        int err = 0;
        for (int j = 0; j < 16; ++j)
        {
            int x = var1[j] - var2[j];
            err += x * x;
        }
        if (ret_err > err)
        {
            ret_err = err;
            ret = i;
        }
    }
    return ret;
}

基本上,它计算每个 uint8_t[16] 块之间的平方差之和,并返回具有最小平方差的块对的索引。那么,那么我用霓虹灯内在函数重写了它(没有特别尝试使其更快,因为这不是重点):

int findMinErr_NEON(uint8_t* var1, uint8_t* var2, int size)
{
    int ret = 0;
    int ret_err = INT_MAX;
    for (int i = 0; i < size / 16; ++i, var1 += 16, var2 += 16)
    {
        int err;
        uint8x8_t var1_0 = vld1_u8(var1 + 0);
        uint8x8_t var1_1 = vld1_u8(var1 + 8);
        uint8x8_t var2_0 = vld1_u8(var2 + 0);
        uint8x8_t var2_1 = vld1_u8(var2 + 8);
        int16x8_t s0 = vreinterpretq_s16_u16(vsubl_u8(var1_0, var2_0));
        int16x8_t s1 = vreinterpretq_s16_u16(vsubl_u8(var1_1, var2_1));
        uint16x8_t u0 = vreinterpretq_u16_s16(vmulq_s16(s0, s0));
        uint16x8_t u1 = vreinterpretq_u16_s16(vmulq_s16(s1, s1));
#ifdef __aarch64__1
        err = vaddlvq_u16(u0) + vaddlvq_u16(u1);
#else
        uint32x4_t err0 = vpaddlq_u16(u0);
        uint32x4_t err1 = vpaddlq_u16(u1);
        err0 = vaddq_u32(err0, err1);
        uint32x2_t err00 = vpadd_u32(vget_low_u32(err0), vget_high_u32(err0));
        err00 = vpadd_u32(err00, err00);
        err = vget_lane_u32(err00, 0);
#endif

        if (ret_err > err)
        {
            ret_err = err;
            ret = i;
#if 0 // enable early exit?
            if (ret_err == 0)
                break;
#endif
        }
    }
    return ret;
}

Now, if (ret_err > err)显然是数据危险。然后我手动“展开”两个循环并修改代码以使用 err0 和 err1 并在执行下一轮计算后检查它们。根据探查器,我得到了一些改进。在简单的 neon 循环中,我将整个函数的大约 30% 花费在这两行中vget_lane_u32其次是if (ret_err > err)。在我展开两次之后,这些操作开始占用 25%(例如,我获得了大约 10% 的整体加速)。另外,检查armv7版本,设置err0时之间只有8条指令(vmov.32 r6, d16[0])以及当它被访问时(cmp r12, r6). T

注意,在代码中提前退出是ifdefed out。启用它会使功能变得更慢。如果我把它展开四个并改为使用四个errN变量并延迟检查两轮然后我仍然看到vget_lane_u32在探查器中花费太多时间。当我检查生成的 asm 时,似乎编译器破坏了所有优化尝试,因为它重用了一些errN有效地使CPU访问结果的寄存器vget_lane_u32比我想要的早得多(我的目标是延迟 10-20 条指令的访问)。仅当我按 4 展开并将所有四个 errN 标记为易失性时vget_lane_u32然而,在剖面仪中完全从雷达上消失了if (ret_err > errN)检查显然变得非常慢,因为现在这些可能最终成为常规堆栈变量,总体而言,4x 手动循环展开中的这 4 次检查开始占用 40%。看起来使用适当的手动 asm 可以使其正常工作:提前退出循环,同时避免 neon->arm 停顿并在循环中包含一些arm逻辑,但是,处理arm asm所需的额外维护使其复杂了10倍在大型项目中维护这种代码(没有任何武器)。

Update:

这是将数据从 neon 移动到 Arm 寄存器时的停顿示例。为了实现早期存在,我需要每个循环从霓虹灯移动到手臂一次。根据 xcode 附带的采样分析器,仅此一步就占用了整个函数的 50% 以上。我尝试在 mov 之前和/或之后添加大量 noop,但似乎没有任何内容影响探查器中的结果。我尝试使用 vorr d0,d0,d0 进行 noops:没有区别。停顿的原因是什么,或者分析器只是显示错误的结果?

enter image description here


None

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

调试 Arm neon 代码中的数据/neon 性能危害 的相关文章

  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • GCC C++ (ARM) 和指向结构体字段的 const 指针

    假设有一个简单的测试代码 typedef struct int first int second int third type t define ADDRESS 0x12345678 define REGISTER type t ADDRE
  • 有什么工具可以说明每种方法运行需要多长时间?

    我的程序的某些部分速度很慢 我想知道是否有我可以使用的工具 例如它可以告诉我可以运行 methodA 花了 100ms 等等 或者类似的有用信息 如果您使用的是 Visual Studio Team System 性能工具 中有一个内置分析
  • 什么是大O表示法?你用它吗? [复制]

    这个问题在这里已经有答案了 什么是大O表示法 你用它吗 我想我错过了这门大学课程 D 有人使用过它并给出一些现实生活中使用它的例子吗 也可以看看 八岁孩子的大O https stackoverflow com questions 10716
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数
  • 使用 z = f(x, y) 形式的 B 样条方法来拟合 z = f(x)

    作为一个潜在的解决方案这个问题 https stackoverflow com questions 76476327 how to avoid creating many binary switching variables in gekk
  • Delphi 的内存分析工具?

    我建立了一个项目并运行它 然后在 Process Explorer 中查看它 结果发现它在启动时使用的 RAM 比我想象的要多 5 倍 现在 如果我的程序运行得太慢 我会将其连接到分析器并让它告诉我什么正在使用我的所有周期 有没有类似的工具
  • CUDA 中指令重放的其他原因

    这是我从 nvprof CUDA 5 5 获得的输出 Invocations Metric Name Metric Description Min Max Avg Device Tesla K40c 0 Kernel MyKernel do
  • 需要一些建议来开始在 ARM(使用 Linux)平台上编程

    我 也许 很快就会在托管 Linux 发行版的 ARM 平台上工作 我不知道哪个发行版 我知道该项目涉及视频流 但我无法告诉你更多信息 其实我只收到通知 还没见到任何人 我从来没有在这样的平台上工作过 所以我的想法是在项目开始之前进行测试
  • 如何在WinMobile6上启用ARMv6非对齐访问?

    ARMv6 引入了一个很棒的功能 未对齐的内存访问 这使得代码中的某些事情变得更加简单和更快 但微软只在winCE6中提供了API 现在大多数 PDA 都基于 WinMobile6 基于 CE 5 x 默认情况下禁用未对齐访问 我尝试在 C
  • Java中的整数缓存[重复]

    这个问题在这里已经有答案了 可能的重复 奇怪的Java拳击 https stackoverflow com questions 3130311 weird java boxing 最近我看到一个演示 其中有以下 Java 代码示例 Inte
  • jQuery.ready() 中应该包含什么内容,哪些内容应该在 jQuery.ready() 之外?

    jQuery ready 中应该包含哪些内容 哪些内容应该包含在 jQuery ready 之外 从性能的角度来看 我在某处读到将所有代码都包装在一个jQuery ready 这不是一个有效的方法 那么我的问题是 什么应该在里面 什么可以在
  • 堆内存与对象内存

    根据一篇关于Java内存和特性的论文 内存分数分为两种类型 堆内存 即应用程序在运行时消耗的内存 对象内存 即程序中使用的各种对象分配的内存 例如整数和字符串等 他们的意思是stack当他们说时的记忆object记忆 或者它们是什么意思 很
  • 网页优化:为什么组合文件速度更快?

    我读过 将所有 css 文件合并为一个大文件 或将所有脚本文件合并为一个脚本文件 可以减少 HTTP 请求的数量 从而加快下载速度 但我不明白这一点 我认为如果你有多个文件 最多有一个限制 我相信在现代浏览器上是 10 个 浏览器会并行下载
  • OpenSSL HMAC 函数中的意外复杂性

    SSL 文档分析 这个问题与 OpenSSL 中 HMAC 例程的使用有关 由于 Openssl 文档在某些领域有点薄弱 分析表明使用 unsigned char HMAC const EVP MD evp md const void ke
  • 比“add esp, 4”更小的指令

    又是我 我的程序中有很多 add esp 4 我正在尝试减小它的大小 是否有任何更小的指令可以替代 add esp 4 pop edx 或者您不介意破坏的任何其他整数寄存器 这就是现代编译器实际上所做的 https stackoverflo
  • 如何找到 Ruby 应用程序中的性能瓶颈?

    我编写了一个 Ruby 应用程序 它可以解析来自不同格式 html xml 和 csv 文件的源的大量数据 如何找出代码的哪些区域花费时间最长 有没有关于如何提高 Ruby 应用程序性能的好资源 或者您是否有始终遵循的性能编码标准 例如 您
  • .ko 文件是如何构建的

    我正在尝试将我自己的驱动程序移植到Beagle 板 xm arm cortex A8 在移植时我试图弄清楚如何 ko文件实际构建 在我们的Makefile我们只有一个命令来构建 o file 怎样是一个 ko文件已建立 使用Linux 2
  • 强制初始化模板类的静态数据成员

    关于模板类的静态数据成员未初始化存在一些问题 不幸的是 这些都没有能够帮助我解决我的具体问题的答案 我有一个模板类 它有一个静态数据成员 必须为特定类型显式实例化 即必须专门化 如果不是这种情况 使用不同的模板函数应该会导致链接器错误 这是
  • 如何缩短 PHP if 语句?

    我有一个 if 语句 我需要将单个字符串与许多不同的选项进行比较 我在下面发布的代码非常清楚地表明了我的意思 我知道有两种方法可以做到这一点 但另一种甚至更长 那么 是否有任何函数可以以更短的方式实现类似的功能 我的要求可能看起来很愚蠢 但

随机推荐

  • 如何解决 Laravel 9 中将 public 更改为 public_html 的问题

    我正在尝试将公共文件夹更改为 Cpanel 上的 public html 文件夹 并且它在我的计算机上的本地模式下工作正常 我尝试了这些步骤 app AppServiceProvider php 添加此代码 public function
  • 扩展原生 JavaScript 数组

    有没有办法从JS原生函数继承类 例如 我有一个这样的JS函数 function Xarray Array apply this arguments some stuff for insert add and remove notificat
  • 如何将MP3文件播放到麦克风输入jQuery

    我正在尝试创建它 以便当用户播放声音时 它会将声音播放到用户的麦克风输入 因此 当他们进行 Skype 通话 游戏聊天 等时 所有用户都会听到该内容 有没有办法在 Javascript jQuery 中向麦克风而不是扬声器播放音乐 如果没有
  • iOS - UIVIewController 中的 UITableView 不显示所有行 [Swift]

    我遇到了一个错误UITableView in UIViewController 我会尝试解释一下情况和我的问题 我有一个TabBarController哪个视图是UIViewController with a UITableView 我不使
  • jsoup - 从维基百科文章中提取文本

    我正在编写一些 Java 代码 以便使用维基百科的文本实现 NLP 任务 如何使用 JSoup 提取维基百科文章的所有文本 例如http en wikipedia org wiki 波士顿 Document doc Jsoup connec
  • CGPath动画

    我需要一些示例代码 可以在其中对曲线 圆弧路径进行动画处理 该路径应该绘制一个完整的圆作为动画 任何意见将不胜感激 谢谢 星期六 UPDATE 意识到这个问题有更好的解决方案 只需创建一个圆形路径并将 CAShapeLayer 的 stro
  • 不带类型的函数参数声明

    在课堂上 我偶然发现了 Excel 工作表的 VBA 代码 它显示了函数的实现 其中参数尚未声明为任何类型 当它被调用时 一个String被用作该参数 Option Explicit The weird function Function
  • 访问单元格范围的函数

    我不知道如何将单元格范围与函数一起使用 我徒劳地搜索了一些例子 我写了下面的测试 我在两个 for 行上都收到 对象变量未设置 错误 一个没有 RangeAddress 第二个带有它 因为我不确定正确的语法 function CHECKBZ
  • 关于php中带有附件的电子邮件

    任何人都可以帮助我吗 我正在尝试发送一封带有附件的电子邮件 它发送了电子邮件 但电子邮件是以编码格式发送的 我认为问题出在标题上 任何人都可以给我工作代码 我尝试过网上有很多现成的代码所有这些 但没有一个在工作 您可以使用PHPMailer
  • R 中的插补

    我是 R 编程语言的新手 我只是想知道有什么方法可以估算空值只有一列在我们的数据集中 因为我见过的所有插补命令和库都会插补整个数据集的空值 这是一个使用的示例Hmisc包装和impute library Hmisc DF lt data f
  • 将 JSON 对象转换为打印精美的 JSON 的 Angular 2 管道

    尝试编写一个 Angular 2 管道 该管道将获取 JSON 对象字符串并返回漂亮的打印 格式以显示给用户 例如 需要这样 id 1 号码 K3483483344 州 CA 活跃 真实 并返回在 HTML 中显示时看起来像这样的内容 所以
  • 如何使用 PHP 让浏览器缓存图像?

    我对如何缓存图像完全陌生 我使用 PHP 输出图库中的所有图像 并希望已显示的图像由浏览器缓存 因此 PHP 脚本不必再次输出相同的图像 我想要的只是图像显示得更快 当调用图像时我喜欢这样 img src showImage php id
  • 根据列中的值与列表中的值匹配来选择 SQL 数据库中的行

    我有一个包含大约 140 万行的表 我想编写一个 sql select 语句 返回列表中第一列 唯一的 id 中存在的所有行 该列表可以包含 1 到 50k 个 ID 并且在每次运行脚本时生成 并且每次都可能不同 根据此列表中的 id 编号
  • Netbeans 8.2 CSS 网格警告和错误

    我收到有关以下规则的警告和错误 data display grid grid column gap 20px grid row gap 10px grid template columns label 150px field 1fr 警告位
  • 如何启用离子多点触控事件

    我正在开发一个简单的离子应用程序 该应用程序的一部分要求您同时按下两个按钮 我这样构建了这个逻辑 a class icon ion qr scanner lg txt a a class icon ion qr scanner lg txt
  • 如何使用 oracle 管理自动备份?

    我正在关注来自的教程甲骨文文档 我发现管理备份 恢复过程的首选方法是使用 RMAN 我已经开始练习它 我的意思是 通过 sql plus cli 但我真的不知道如何使该过程自动化 然后我看到在 sql Developer dba 面板中 有
  • 在对象上找不到参数 [com.android.support:appcompat-v7:25.4.0] 的方法实现()...android

    我必须编译一个在线购买的项目 将其导入 android studio 时 它抱怨 gradle 版本 所以我将 distributionUrl 更新为这个distributionUrl https services gradle org d
  • 如何在两个div之间画一条线?

    我目前正在尝试在一个 div 的右下角到另一个 div 的右上角之间绘制一条对角线 如果可能的话 我想不用 jQuery 来完成它 这可能吗 http jsfiddle net cnmsc1tm 由于 CSS 限制 这不适用于 IE8 或更
  • 删除 jQuery Mobile 滑块控件中的文本框

    我正在使用这个 JQM 链接 我在分区中使用了滑块 在旧版本中我使用了属性 class ui hidden accessible 因为没有在滑块旁边显示文本框 但在此
  • 调试 Arm neon 代码中的数据/neon 性能危害

    最初 当我尝试时出现了问题优化算法根据 Profiler 的数据 Neon Arm 和其中的一小部分占据了 80 我尝试测试看看可以采取哪些措施来改进它 为此我创建了指向优化函数的不同版本的函数指针数组 然后在循环中运行它们以在探查器中查看