免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3966 | 回复: 11
打印 上一主题 下一主题

字节对齐效率的疑惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-15 09:20 |只看该作者 |倒序浏览
本帖最后由 lyjdamzwf 于 2012-01-15 09:21 编辑

平时大家一直都在说字节对齐会影响效率如何如何, 最近突然想自己测一下这个问题.
首先我想到了glibc中的memset中对于字节对齐的处理,代码如下:
  1. void *
  2. memset (dstpp, c, len)
  3.      void *dstpp;
  4.      int c;
  5.      size_t len;
  6. {
  7.   long int dstp = (long int) dstpp;

  8.   if (len >= 8)
  9.     {
  10.       size_t xlen;
  11.       op_t cccc;

  12.       cccc = (unsigned char) c;
  13.       cccc |= cccc << 8;
  14.       cccc |= cccc << 16;
  15.       if (OPSIZ > 4)
  16.     /* Do the shift in two steps to avoid warning if long has 32 bits.  */
  17.     cccc |= (cccc << 16) << 16;

  18.       [color=Red]/* There are at least some bytes to set.
  19.      No need to test for LEN == 0 in this alignment loop.  */
  20.       while (dstp % OPSIZ != 0)
  21.     {
  22.       ((byte *) dstp)[0] = c;
  23.       dstp += 1;
  24.       len -= 1;
  25.     }[/color]

  26.       /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
  27.       xlen = len / (OPSIZ * 8);
  28.       while (xlen > 0)
  29.     {
  30.       ((op_t *) dstp)[0] = cccc;
  31.       ((op_t *) dstp)[1] = cccc;
  32.       ((op_t *) dstp)[2] = cccc;
  33.       ((op_t *) dstp)[3] = cccc;
  34.       ((op_t *) dstp)[4] = cccc;
  35.       ((op_t *) dstp)[5] = cccc;
  36.       ((op_t *) dstp)[6] = cccc;
  37.       ((op_t *) dstp)[7] = cccc;
  38.       dstp += 8 * OPSIZ;
  39.       xlen -= 1;
  40.     }

  41. len %= OPSIZ * 8;

  42.       /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
  43.       xlen = len / OPSIZ;
  44.       while (xlen > 0)
  45.     {
  46.       ((op_t *) dstp)[0] = cccc;
  47.       dstp += OPSIZ;
  48.       xlen -= 1;
  49.     }
  50.       len %= OPSIZ;
  51.     }

  52.   /* Write the last few bytes.  */
  53.   while (len > 0)
  54.     {
  55.       ((byte *) dstp)[0] = c;
  56.       dstp += 1;
  57.       len -= 1;
  58.     }

  59.   return dstpp;
  60. }
复制代码
我们可以看到红色部分,memset进行了按4字节或8字节对齐地字节赋值(OPSIZ为4或8, 在地址对齐之后, 才开始按效率较高的4bytes/8bytes 赋值.
在我以前的理解是, 如果地址没有按某标准类型大小对齐时, 我们在取某标准类型值的时候, 总线会花费更多的指令来读取"两块"地址, 然后合并取值, 导致效率降低.
带着这样的猜测, 我编写了如下测试程序:
  1. #include <sys/time.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <iostream>
  7. using namespace std;

  8. #define EXEC_COUNT      (1000 * 1000 * 1000)

  9. typedef long int        op_t;

  10. int main(int argc_, char* argv_[])
  11. {
  12.     void* ori_mem_ptr = malloc(50);
  13.     memset(ori_mem_ptr, 0, sizeof(ori_mem_ptr));

  14.     timeval begin_tv;
  15.     timeval end_tv;
  16.     for (int offset = 0; offset < 20; ++offset)
  17.     {
  18.         char* mem_ptr = (char*)ori_mem_ptr + offset;
  19.         long int ptr_val = (long int)mem_ptr;

  20.         printf("ori_mem_ptr:[%p] mem_ptr:[%p] offset:[%d]\n", ori_mem_ptr, mem_ptr, offset);
  21.         gettimeofday(&begin_tv, NULL);

  22.         for (uint32_t i = 0; i < EXEC_COUNT; ++i)
  23.         {
  24.             *(uint32_t*)mem_ptr = i;
  25.             //! uint32_t tmp_val = *(uint32_t*)mem_ptr;
  26.         }

  27.         gettimeofday(&end_tv, NULL);
  28.         printf("perf:[%lu]us\n\n", (end_tv.tv_sec * 1000 * 1000 + end_tv.tv_usec) - (begin_tv.tv_sec * 1000 * 1000 + begin_tv.tv_usec));
  29.     }

  30.     free(ori_mem_ptr);

  31.     return 0;
  32. }
复制代码
这样一个简单的程序, 分配了一个内存块, 然后分配偏移指针指向其内部不同的地址, 本意是想测出没有按字节对齐的话, 取值效率会慢, 但是测试结果让我感到疑惑.ori_mem_ptr:[0x18af010] mem_ptr:[0x18af010] offset:[0]
perf:[2736881]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af011] offset:[1]
perf:[2730324]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af012] offset:[2]
perf:[2728421]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af013] offset:[3]
perf:[2704567]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af014] offset:[4]
perf:[2711222]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af015] offset:[5]
perf:[2710743]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af016] offset:[6]
perf:[2715045]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af017] offset:[7]
perf:[2720721]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af018] offset:[8]
perf:[2707865]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af019] offset:[9]
perf:[2750098]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01a] offset:[10]
perf:[2745997]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01b] offset:[11]
perf:[2686419]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01c] offset:[12]
perf:[2686714]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01d] offset:[13]
perf:[3304225]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01e] offset:[14]
perf:[3299947]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af01f] offset:[15]
perf:[3303989]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af020] offset:[16]
perf:[2747328]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af021] offset:[17]
perf:[2687445]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af022] offset:[18]
perf:[2703295]us

ori_mem_ptr:[0x18af010] mem_ptr:[0x18af023] offset:[19]
perf:[2688810]us


可以看到输出结果的分界点不是按我所想的那样, 我怀疑是不是虚拟地址是如此, 但是实际的物理地址可以不连续导致, 那如果这样memset这些库函数的做法又让我疑惑了. 对底层不是很懂.
希望CU各位大神能帮我解惑.


论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
2 [报告]
发表于 2012-01-15 09:44 来自手机 |只看该作者
编译器优化或gettimeofday的不准确性?

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
3 [报告]
发表于 2012-01-16 09:24 |只看该作者
应该是对齐与否赋值的开销差别远比循环的开销小,再加上系统调度的差别,看不出来差别

论坛徽章:
12
巳蛇
日期:2013-09-16 15:32:242015年辞旧岁徽章
日期:2015-03-03 16:54:152015年亚洲杯之约旦
日期:2015-02-11 14:38:37双鱼座
日期:2015-01-05 11:05:47戌狗
日期:2014-12-08 09:41:18戌狗
日期:2014-08-15 09:29:29双子座
日期:2014-08-05 09:17:17卯兔
日期:2014-06-08 15:32:18巳蛇
日期:2014-01-27 08:47:08白羊座
日期:2013-11-28 21:04:15巨蟹座
日期:2013-11-13 21:58:012015年亚洲杯之科威特
日期:2015-04-17 16:51:51
4 [报告]
发表于 2012-01-16 10:07 |只看该作者
访存指令地址对齐与否,在支持非对齐访存的CPU上一条指令也就是差几个到几十个周期,这么测可能测不出来。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2012-01-16 10:11 |只看该作者
你直接用汇编写,循环1亿次
用time ./a.out测试
对齐不对齐差2倍速度最少的

论坛徽章:
0
6 [报告]
发表于 2012-01-16 10:39 |只看该作者
本帖最后由 狗气球 于 2012-01-16 10:41 编辑

和CPU架构的关系大不大?
对RISC和x86的影响程度是否一样?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
7 [报告]
发表于 2012-01-16 20:23 |只看该作者
lyjdamzwf 发表于 2012-01-15 09:20
平时大家一直都在说字节对齐会影响效率如何如何, 最近突然想自己测一下这个问题.
首先我想到了glibc中的me ...

不必太在意这个效率。
不过,这种程序移植到其它CPU可能会崩溃,尽量不要这么用。

论坛徽章:
1
射手座
日期:2013-08-21 13:11:46
8 [报告]
发表于 2012-01-16 20:27 |只看该作者
狗气球 发表于 2012-01-16 10:39
和CPU架构的关系大不大?
对RISC和x86的影响程度是否一样?


有些RISC如果不对齐,直接会中断的

论坛徽章:
0
9 [报告]
发表于 2012-01-17 07:26 |只看该作者
多谢各位的评论, 之后我又测试了不同的类型长度的访存操作, 不同的cpu型, 测试结果均比较无规律化, 有的性能上没有明显的差别, 有的会出现比较奇怪的"分界", 个人觉得可能glibc的用意主要还是如LS几位所说, 为了防止其他一些硬件架构不对齐会中断的问题.

论坛徽章:
0
10 [报告]
发表于 2012-01-17 08:38 |只看该作者
回复 9# lyjdamzwf


    建议看一下反汇编。这会儿没空不然我也编两个看看了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP