memcpy多字节字节赋值问题

简介:

   以前没注意过多字节赋值问题,考虑的角度是充分利用 cpu 的 32 位带宽。一次复制 1 个字节和一次复制 4 个字节占用的 cpu 指令周期是一样的,既然我们的 cpu 能同时操作 32 位,为什么我们不能一次复制 4 个字节呢?如此一来,总运行的指令数将降低到原来的 1/4 !

 

于是有下面代码(henix转自http://www.embedded.com/columns/technicalinsights/19205567?_requestid=212290):


 1 void *memcpy(void *dest, void *src, size_t count)
 2 {
 3     size_t c = count >> 2; /* 相当于 count / 4 */
 4     long *pt;
 5     const long *ps;
 6     if (c)
 7     {
 8         /* 首先按 4 个字节复制 */
 9         pt = (long *) dest;
10         ps = (const long *) src;
11         while (c)
12         {
13             *pt = *ps;
14             pt++;
15             ps++;
16             c--;
17         }
18     }
19     c = count & 3; /* 得到 count 模 4 的余数 */
20     if (c)
21     {
22         /* 如果有剩下的,再按 1 个字节复制剩余的 */
23         char *pct = (char *) pt;
24         const char *pcs = (const char *) ps;
25         while (c)
26         {
27             *pct = *pcs;
28             pct++;
29             pcs++;
30             c--;
31         }
32     }
33     return dest;
34 }


通过使用 long 型指针,强行按 4 个字节复制。

 

 

还有对 3 种 memcpy 实现的对比,上述算法受到地址对齐的影响较为严重。在地址按4 字节对齐的时候,上述算法的效率比单字节 memcpy 实现高很多,但如果地址没有按4 字节对齐,则其效率并不高,有时甚至还比普通 memcpy 还低。这可能是因为,虽然上述算法减少了 cpu 的指令数,但内存的速度比 cpu 慢得多,速度的瓶颈还是在内存。

 

 

 

刚看了一份memcpy的实现,为了解决字节对齐的问题,从128开始,依次减少,直到1个字节。原文在http://code.google.com/p/dingoo-sdk/source/browse/trunk/dingoo_sdk/src/libc/memcpy.c?spec=svn180&r=180

贴出如下:


#include "string.h" 

 #include <stdint.h> 

   

   

   

 inline void _memcpy_1x1(void* dst, const void* src) { 

         asm( 

                 "lb $t0, 0(%0)\n\t"

                 "sb $t0, 0(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_2x1(void* dst, const void* src) { 

         asm( 

                 "lh $t0, 0(%0)\n\t"

                 "sh $t0, 0(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x1(void* dst, const void* src) { 

         asm( 

                 "lw $t0, 0(%0)\n\t"

                 "sw $t0, 0(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x2(void* dst, const void* src) { 

         asm( 

                 "lw $t0, 0(%0)\n\t"

                 "lw $t1, 4(%0)\n\t"

                 "sw $t0, 0(%1)\n\t"

                 "sw $t1, 4(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x4(void* dst, const void* src) { 

         asm( 

                 "lw $t0,  0(%0)\n\t"

                 "lw $t1,  4(%0)\n\t"

                 "lw $t2,  8(%0)\n\t"

                 "lw $t3, 12(%0)\n\t"

                 "sw $t0,  0(%1)\n\t"

                 "sw $t1,  4(%1)\n\t"

                 "sw $t2,  8(%1)\n\t"

                 "sw $t3, 12(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x8(void* dst, const void* src) { 

         asm( 

                 "lw $t0,  0(%0)\n\t"

                 "lw $t1,  4(%0)\n\t"

                 "lw $t2,  8(%0)\n\t"

                 "lw $t3, 12(%0)\n\t"

                 "lw $t4, 16(%0)\n\t"

                 "lw $t5, 20(%0)\n\t"

                 "lw $t6, 24(%0)\n\t"

                 "lw $t7, 28(%0)\n\t"

                 "sw $t0,  0(%1)\n\t"

                 "sw $t1,  4(%1)\n\t"

                 "sw $t2,  8(%1)\n\t"

                 "sw $t3, 12(%1)\n\t"

                 "sw $t4, 16(%1)\n\t"

                 "sw $t5, 20(%1)\n\t"

                 "sw $t6, 24(%1)\n\t"

                 "sw $t7, 28(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x16(void* dst, const void* src) { 

         asm( 

                 "lw $t0,  0(%0)\n\t"

                 "lw $t1,  4(%0)\n\t"

                 "lw $t2,  8(%0)\n\t"

                 "lw $t3, 12(%0)\n\t"

                 "lw $t4, 16(%0)\n\t"

                 "lw $t5, 20(%0)\n\t"

                 "lw $t6, 24(%0)\n\t"

                 "lw $t7, 28(%0)\n\t"

                 "lw $t8, 32(%0)\n\t"

                 "lw $t9, 36(%0)\n\t"

   

                 "sw $t0,  0(%1)\n\t"

                 "lw $t0, 40(%0)\n\t"

                 "sw $t1,  4(%1)\n\t"

                 "lw $t1, 44(%0)\n\t"

                 "sw $t2,  8(%1)\n\t"

                 "lw $t2, 48(%0)\n\t"

                 "sw $t3, 12(%1)\n\t"

                 "lw $t3, 52(%0)\n\t"

                 "sw $t4, 16(%1)\n\t"

                 "lw $t4, 56(%0)\n\t"

                 "sw $t5, 20(%1)\n\t"

                 "lw $t5, 60(%0)\n\t"

   

                 "sw $t6, 24(%1)\n\t"

                 "sw $t7, 28(%1)\n\t"

                 "sw $t8, 32(%1)\n\t"

                 "sw $t9, 36(%1)\n\t"

   

                 "sw $t0, 40(%1)\n\t"

                 "sw $t1, 44(%1)\n\t"

                 "sw $t2, 48(%1)\n\t"

                 "sw $t3, 52(%1)\n\t"

                 "sw $t4, 56(%1)\n\t"

                 "sw $t5, 60(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

 inline void _memcpy_4x32(void* dst, const void* src) { 

         asm( 

                 "lw $t0,   0(%0)\n\t"

                 "lw $t1,   4(%0)\n\t"

                 "lw $t2,   8(%0)\n\t"

                 "lw $t3,  12(%0)\n\t"

                 "lw $t4,  16(%0)\n\t"

                 "lw $t5,  20(%0)\n\t"

                 "lw $t6,  24(%0)\n\t"

                 "lw $t7,  28(%0)\n\t"

                 "lw $t8,  32(%0)\n\t"

                 "lw $t9,  36(%0)\n\t"

   

                 "sw $t0,   0(%1)\n\t"

                 "lw $t0,  40(%0)\n\t"

                 "sw $t1,   4(%1)\n\t"

                 "lw $t1,  44(%0)\n\t"

                 "sw $t2,   8(%1)\n\t"

                 "lw $t2,  48(%0)\n\t"

                 "sw $t3,  12(%1)\n\t"

                 "lw $t3,  52(%0)\n\t"

                 "sw $t4,  16(%1)\n\t"

                 "lw $t4,  56(%0)\n\t"

                 "sw $t5,  20(%1)\n\t"

                 "lw $t5,  60(%0)\n\t"

                 "sw $t6,  24(%1)\n\t"

                 "lw $t6,  64(%0)\n\t"

                 "sw $t7,  28(%1)\n\t"

                 "lw $t7,  68(%0)\n\t"

                 "sw $t8,  32(%1)\n\t"

                 "lw $t8,  72(%0)\n\t"

                 "sw $t9,  36(%1)\n\t"

                 "lw $t9,  76(%0)\n\t"

   

                 "sw $t0,  40(%1)\n\t"

                 "lw $t0,  80(%0)\n\t"

                 "sw $t1,  44(%1)\n\t"

                 "lw $t1,  84(%0)\n\t"

                 "sw $t2,  48(%1)\n\t"

                 "lw $t2,  88(%0)\n\t"

                 "sw $t3,  52(%1)\n\t"

                 "lw $t3,  92(%0)\n\t"

                 "sw $t4,  56(%1)\n\t"

                 "lw $t4,  96(%0)\n\t"

                 "sw $t5,  60(%1)\n\t"

                 "lw $t5, 100(%0)\n\t"

                 "sw $t6,  64(%1)\n\t"

                 "lw $t6, 104(%0)\n\t"

                 "sw $t7,  68(%1)\n\t"

                 "lw $t7, 108(%0)\n\t"

                 "sw $t8,  72(%1)\n\t"

                 "lw $t8, 112(%0)\n\t"

                 "sw $t9,  76(%1)\n\t"

                 "lw $t9, 116(%0)\n\t"

   

                 "sw $t0,  80(%1)\n\t"

                 "lw $t0, 120(%0)\n\t"

                 "sw $t1,  84(%1)\n\t"

                 "lw $t1, 124(%0)\n\t"

   

                 "sw $t2,  88(%1)\n\t"

                 "sw $t3,  92(%1)\n\t"

                 "sw $t4,  96(%1)\n\t"

                 "sw $t5, 100(%1)\n\t"

                 "sw $t6, 104(%1)\n\t"

                 "sw $t7, 108(%1)\n\t"

                 "sw $t8, 112(%1)\n\t"

                 "sw $t9, 116(%1)\n\t"

   

                 "sw $t0, 120(%1)\n\t"

                 "sw $t1, 124(%1)\n\t"

                 : : "r"(dst), "r"(src) 

         ); 

 } 

   

   

   

 inline void _memcpy_down_1(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 1) { 

                 _memcpy_1x1(dst, src); 

                 dst += 1; 

                 src += 1; 

         } 

 } 

   

 inline void _memcpy_down_2(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 2) { 

                 _memcpy_2x1(dst, src); 

                 dst += 2; 

                 src += 2; 

         } 

         _memcpy_down_1(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_4(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 4) { 

                 _memcpy_4x1(dst, src); 

                 dst += 4; 

                 src += 4; 

         } 

         _memcpy_down_2(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_8(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 8) { 

                 _memcpy_4x2(dst, src); 

                 dst += 8; 

                 src += 8; 

         } 

         _memcpy_down_4(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_16(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 16) { 

                 _memcpy_4x4(dst, src); 

                 dst += 16; 

                 src += 16; 

         } 

         _memcpy_down_8(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_32(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 32) { 

                 _memcpy_4x8(dst, src); 

                 dst += 32; 

                 src += 32; 

         } 

         _memcpy_down_16(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_64(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 64) { 

                 _memcpy_4x16(dst, src); 

                 dst += 64; 

                 src += 64; 

         } 

         _memcpy_down_32(dst, src, dst_end); 

 } 

   

 inline void _memcpy_down_128(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         if(((uintptr_t)dst_end - (uintptr_t)dst) >= 128) { 

                 _memcpy_4x32(dst, src); 

                 dst += 128; 

                 src += 128; 

         } 

         _memcpy_down_64(dst, src, dst_end); 

 } 

   

   

   

 inline void _memcpy_1(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 1); dst += 1, src += 1) 

                 _memcpy_1x1(dst, src); 

 } 

   

 inline void _memcpy_2(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 2); dst += 2, src += 2) 

                 _memcpy_2x1(dst, src); 

         _memcpy_down_1(dst, src, dst_end); 

 } 

   

 inline void _memcpy_4(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 4); dst += 4, src += 4) 

                 _memcpy_4x1(dst, src); 

         _memcpy_down_2(dst, src, dst_end); 

 } 

   

 inline void _memcpy_8(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 8); dst += 8, src += 8) 

                 _memcpy_4x2(dst, src); 

         _memcpy_down_4(dst, src, dst_end); 

 } 

   

 inline void _memcpy_16(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 16); dst += 16, src += 16) 

                 _memcpy_4x4(dst, src); 

         _memcpy_down_8(dst, src, dst_end); 

 } 

   

 inline void _memcpy_32(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 32); dst += 32, src += 32) 

                 _memcpy_4x8(dst, src); 

         _memcpy_down_16(dst, src, dst_end); 

 } 

   

 inline void _memcpy_64(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 64); dst += 64, src += 64) 

                 _memcpy_4x16(dst, src); 

         _memcpy_down_32(dst, src, dst_end); 

 } 

   

 inline void _memcpy_128(uint8_t* dst, const uint8_t* src, uint8_t* dst_end) { 

         for(; dst <= (dst_end - 128); dst += 128, src += 128) 

                 _memcpy_4x32(dst, src); 

         _memcpy_down_64(dst, src, dst_end); 

 } 

   

   

   

 void* _memcpy_fast(void* dst, const void* src, uintptr_t size) { 

         if((dst == NULL) || (src == NULL)) 

                 return NULL; 

   

         uint8_t*       _dst = (uint8_t*)dst; 

         uint8_t*       _dst_end = &_dst[size]; 

         const uint8_t* _src = (const uint8_t*)src; 

   

         if((((uintptr_t)_dst & 1) != 0) && (((uintptr_t)_dst & 1) == ((uintptr_t)_src & 1)) && ((_dst + 1) <= _dst_end)) { 

                 _memcpy_1x1(_dst, _src); 

                 _dst += 1; _src += 1; 

         } 

         if(((uintptr_t)_dst & 1) == 0) { 

                 if((((uintptr_t)_dst & 3) != 0) && (((uintptr_t)_dst & 3) == ((uintptr_t)_src & 3)) && ((_dst + 2) <= _dst_end)) { 

                         _memcpy_2x1(_dst, _src); 

                         _dst += 2; _src += 2; 

                 } 

                 if(((uintptr_t)_dst & 3) == 0) { 

                         if((((uintptr_t)_dst & 7) != 0) && (((uintptr_t)_dst & 7) == ((uintptr_t)_src & 7)) && ((_dst + 4) <= _dst_end)) { 

                                 _memcpy_4x1(_dst, _src); 

                                 _dst += 4; _src += 4; 

                         } 

                         if(((uintptr_t)_dst & 7) == 0) { 

                                 _memcpy_128(_dst, _src, _dst_end); 

                         } else _memcpy_4(_dst, _src, _dst_end); 

                 } else _memcpy_2(_dst, _src, _dst_end); 

         } else _memcpy_1(_dst, _src, _dst_end); 

   

         return dst; 

 } 


目录
相关文章
|
存储 安全 编译器
内存对齐:C/C++编程中的重要性和技巧
内存对齐:C/C++编程中的重要性和技巧
728 1
|
存储 SQL 关系型数据库
ClickHouse(02)ClickHouse架构设计介绍概述与ClickHouse数据分片设计
ClickHouse的核心架构包括执行过程和数据存储两部分。执行过程涉及Parser与Interpreter解析SQL,通过Column、DataType、Block、Functions和Storage模块处理数据。Column是内存中列的表示,Field处理单个值,DataType负责序列化和反序列化,Block是内存中表的子集,Block Streams处理数据流。Storage代表表,使用不同的引擎如StorageMergeTree。数据存储基于分片和副本,1个分片由多个副本组成,每个节点只能拥有1个分片。
1039 0
ClickHouse(02)ClickHouse架构设计介绍概述与ClickHouse数据分片设计
|
搜索推荐 Java 数据库
基于SpringBoot校园二手书交易管理系统
基于SpringBoot校园二手书交易管理系统
|
并行计算 TensorFlow 调度
推荐场景GPU优化的探索与实践:CUDA Graph与多流并行的比较与分析
RTP 系统(即 Rank Service),是一个面向搜索和推荐的 ranking 需求,支持多种模型的在线 inference 服务,是阿里智能引擎团队沉淀多年的技术产品。今年,团队在推荐场景的GPU性能优化上又做了新尝试——在RTP上集成了Multi Stream,改变了TensorFlow的单流机制,让多流的执行并行,作为增加GPU并行度的另一种选择。本文详细介绍与比较了CUDA Graph与多流并行这两个方案,以及团队的实践成果与心得。
|
监控 Shell Linux
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
554 0
|
3月前
|
机器学习/深度学习 算法
Proximal SFT:用PPO强化学习机制优化SFT,让大模型训练更稳定
本文介绍了一种改进的监督微调方法——Proximal Supervised Fine-Tuning (PSFT),旨在解决传统SFT易过拟合、泛化能力差及导致“熵坍塌”的问题。受PPO强化学习算法启发,PSFT通过引入参数更新的稳定性机制,防止模型在训练中变得过于确定,从而提升探索能力与后续强化学习阶段的表现。实验表明,PSFT在数学推理、模型对齐及泛化能力方面均优于传统SFT。
322 3
Proximal SFT:用PPO强化学习机制优化SFT,让大模型训练更稳定
|
存储 缓存 算法
深入剖析 Qt QHash :原理、应用与技巧
深入剖析 Qt QHash :原理、应用与技巧
880 0
|
敏捷开发 数据可视化 测试技术
【Docker项目实战】使用Docker部署nullboard任务管理工具
【5月更文挑战第14天】使用Docker部署nullboard任务管理工具
606 4
|
编译器 C语言
【C语言】深入理解NULL指针
【C语言】深入理解NULL指针
|
缓存 搜索推荐
【电脑知识】Edge浏览器的使用技巧(特别详细)
【电脑知识】Edge浏览器的使用技巧(特别详细)
775 0