首页 > 其他分享 >使用SIMD思想进行memcpy的优化

使用SIMD思想进行memcpy的优化

时间:2024-10-29 18:18:52浏览次数:6  
标签:src 字节 dst SIMD 优化 memcpy size

一、背景

在嵌入式平台里,arm64是一个非常常用的平台,arm64虽然在单核性能上要弱于x86,但是在指令集方面功能性上要更强,更有操作空间,具体来说,对于arm64v8架构的cpu平台,有SIMD的指令集的支持,使用SIMD可以做一些局部代码逻辑上的极致优化,但是,并不是所有的情形都可以用SIMD指令来提升性能,就比如memcpy这个场景,直接用纯SIMD指令比如下图中的纯SIMD指令的使用相比C库原生的memcpy并不能提升性能,甚至还略差。

本文讲的对memcpy的优化,是借助SIMD的思想,而不是直接用SIMD的命令,思路就是在arm64平台上嵌入汇编把memcpy时使用的寄存器又C库里的64位扩大到armv8支持的128位的寄存器

二、实现代码

/*
- 综合测试出来,用这个函数的性能最好,相比原memcpy有30-40%的提升
- 如果这块数据是一块新数据的话,则有更大的如到40%的提升
*/
attribute((optimize("O3")))void memcpy_neon1(void* dst, const void* src, size_t size) {
    size_t i;
    size_t simd_size = size / 128;     // 每次复制128个字节(16个字节 * 8个向量)
    size_t remainder = size % 128;     // 剩余字节数

    uint8_t* dst_ptr = (uint8_t*)dst;
    const uint8_t* src_ptr = (const uint8_t*)src;

    /*
    * 这里做prefetch,其收益还是有的,可以大致的测出相比不做prefetch有5~10%的收益
    * 另外c库的实现也是带着这个prfm的
    */
    asm volatile("prfm pldl1keep, [%[address]]"
        :
    : [address] "r" (src_ptr)
        : );

    for (i = 0; i < simd_size; i++) {
        uint8x16_t q0, q1, q2, q3, q4, q5, q6, q7;
        // 从源地址加载128个字节
        asm volatile("ldp %q[q0], %q[q1], [%[src]], #32\n"
            "ldp %q[q2], %q[q3], [%[src]], #32\n"
            "ldp %q[q4], %q[q5], [%[src]], #32\n"
            "ldp %q[q6], %q[q7], [%[src]], #32\n"
            : [q0] "=w"(q0), [q1] "=w"(q1), [q2] "=w"(q2), [q3] "=w"(q3),
            [q4] "=w"(q4), [q5] "=w"(q5), [q6] "=w"(q6), [q7] "=w"(q7),
            [src] "+r"(src_ptr));

        // 将128个字节存储到目标地址
        asm volatile("stp %q[q0], %q[q1], [%[dst]], #32\n"
            "stp %q[q2], %q[q3], [%[dst]], #32\n"
            "stp %q[q4], %q[q5], [%[dst]], #32\n"
            "stp %q[q6], %q[q7], [%[dst]], #32\n"
            : [dst] "+r"(dst_ptr)
            : [q0] "w"(q0), [q1] "w"(q1), [q2] "w"(q2), [q3] "w"(q3),
            [q4] "w"(q4), [q5] "w"(q5), [q6] "w"(q6), [q7] "w"(q7));
    }

    // 处理剩余的字节
    memcpy(dst_ptr, src_ptr, remainder);
}

上文中的函数名字是memcpy_neon1,其实还有一个memcpy_neon0,在第三章里的测试结果里会体现他们之间的实测效果差异。memcpy_neon1和memcpy_neon0的实现基本是一摸一样的,仅仅在于memcpy_neon1使用prfm预取,也只是预取了一次,预取了多少其实和arch相关,与cache的hw prefetch配置和cache line的size都相关,这块细节会在处理器架构的后续章节里展开描述。从测试结果上来看,带上prfm性能相对更高,但是要注意,prfm不能每个循环都做,只做一次也就是首地址去做预取才能有收益,做得多实测下来还是负收益。另外,补充一点,你不用担心预取导致的数据不一致问题,因为带OS的系统上cache都有如MESI的缓冲一致性的协议,数据的变更会因为协议而及时同步到SMP里的其他核上

三、实测对比的注意事项及结果对比

3.1 实测对比需要注意的事项

1)对比测试时,需要尽量都使用新的内存,避免数据块已经拷贝一次导致的数据进入cache后读取速度变快而造成结果上的误判。或者说,可以进行时序上的颠倒,比如先测C库的memcpy,再测优化后的memcpy,测出结果以后,再返过来顺序,先测优化后的memcpy,再测C库的memcpy,来对比看,排除掉cache的影响

2)memcpy的src和dst的首地址在8字节对齐时优化后的memcpy提升的性能更加明显,如果首地址不是8字节对齐的,4字节对齐或者无对齐,提升的效果递减。这是源自于ldp和stp的读取128bit的内容时,8字节对齐的数据会让其汇编的读取执行更加的高效

3.2 实测结果对比

测试结果:

测的256到32768字节这个数据量的memcpy,使用我写的memcpy,相比C库的memcpy有30-40%的提升

下图的cost单位是ns

图中neon0和neon1是两个差不多的实现,都用了SIMD,neon0没有使用prfm,neon1使用了prfm。可以看到neon1的性能相对更高,所以最后使用的是memcpy_neon1这个实现,见第二章的实现代码

标签:src,字节,dst,SIMD,优化,memcpy,size
From: https://blog.csdn.net/weixin_42766184/article/details/143327718

相关文章

  • Maxwell参数化建模和优化设计(下)
    本文摘要(由AI生成):本文主要介绍了ANSYSMaxwell优化设计工具的使用方法,包括温度参数化、外电路参数化、网格参数化、求解设置参数化等。同时,还介绍了ANSYSDesignXplorer和ANSYSoptiSLang两种优化工具的使用方法,以及如何进行响应面与Pareto图分析。最后,通过一个电机模型的优化......
  • 重要webpack性能优化
    1.webpack优化打包构建速度-开发体验和效率优化babel-loader缓存:cacheDirectory,只要加了这个,es6代码中没有改动的就不会重新编译,集中缓存,加快速度。IgnorePlugin避免引入无用模块比如有个Moment.js库支持很多语言避免引入过多的语言,动态引入。noParse避免重复......
  • 最短的可以造成崩溃且编译器无法优化掉的 C代码是什么
    在C语言中,编写能够造成崩溃且难以被编译器优化掉的代码通常涉及到未定义的行为(undefinedbehavior)或者对底层内存的非法操作。应当注意的是,未定义的行为是C和C++中应该避免的,因为它使得程序的行为无法预测,可能导致不同编译器或不同平台上产生不同的结果。一、最短的可以造成崩......
  • 【学习笔记】dp 优化
    单调栈&单调队列没啥好说的。放两道题目。线段树优化dp例题CF115ELinearKingdomRaces容易想到记\(f_{i,j}\)表示前\(i\)个跑道,\([i-j+1,i]\)全部修好的最大利润,但不好优化。考虑转化为表示\([j,i]\)全部修好的最大利润。最简单的状态转移方程:\[f_{i,j}=f_{i-1,......
  • 多平台服务中的代码混淆与内存安全:ArkTS 应用的安全优化
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在开发跨平台应用时,代码安全与内存管......
  • 高性能 ArkUI 应用开发:复杂 UI 场景中的内存管理与 XML 优化
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在开发高性能ArkUI应用时,尤其是涉及......
  • 清华:细粒度强化学习优化LLM工具使用
    ......
  • 人大:优化工具文档提升LLM工具使用
    ......
  • GaussDB基于智能化(AI)技术,打造AI4DB和DB4AI两大技术高地,重构数据库内核核心组件,提升数
    云原生为迎接智能化提供了基础条件,智能化是GaussDB的新的牵引方向,两者相辅相成,互相促进。在智能化出现之前,数据库的运维管理主要依赖分层解耦、化繁为简方式来治理,通过人工服务对单点的业务进行管理。但在云化环境中,一个Region纳管上万实例,仅靠人工很难满足业务诉求,这就促成智能与......
  • 智能关键技术三:智能优化器
    贝叶斯网络模型原理贝叶斯网络是一种概率图模型,拓扑结构通常为一个有向无环图。贝叶斯网络的优势在于能够利用条件独立假设对多变量数据进行建模,并且自适应变量之间的相关性,具体是指每个变量的概率分布只和与它直接连接的父亲节点有关。使用这种方法能够比基于简单的独立性假设的......