免费注册 查看新帖 |

Chinaunix

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

[函数] calloc函数的效率 [复制链接]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-09-09 09:53 |只看该作者 |倒序浏览
昨天上网,看到一些代码用calloc函数写的。申请内存的函数,平时不常用。因为不常用,所以见了便想它为什么不常用呢?是不是它和malloc+memset函数的效率有差别啊?所以写了验证程序,一看,果然如此,calloc函数的效率要比malloc+memset函数的效率低一点。测试如下:

环境:

  1. Red Hat Linux release 8.0 (Psyche)
  2. Kernel 2.4.18-14smp on an i686
  3. login: yangwl
  4. Password:
复制代码


测试办法:用calloc函数申请100个字节的空间,申请1亿次,记时。用malloc+memset函数完成同样的工作,记时。比较两次记时的大小。

自己猜想后简单的测试代码及结果:

  1. [yangwl:/home/users50/yangwl/test]$ cat time.c
  2. #include <stdio.h>;
  3. #include <stdlib.h>;
  4. #include <time.h>;
  5. #include <string.h>;

  6. int main(void) {
  7.         int     i;
  8.         char    *p;
  9.         time_t  t;

  10.         t = time(0);
  11.         printf("begin...\n");
  12.         for ( i = 0; i < 100000000; i++) {
  13. #ifdef CA
  14.                 p = (char *)calloc(100,sizeof(char));
  15. #endif
  16. #ifdef MA
  17.                 p = (char *)malloc(100*sizeof(char));
  18.                 memset(p,0,100);
  19. #endif
  20.                 if ( p == NULL ) {
  21.                         printf("calloc error!\n");
  22.                         exit(1);
  23.                 }
  24.                 free(p);
  25.         }
  26.         t = time(0) - t;
  27.         printf("%ld\n",t);
  28.         exit(0);
  29. }
  30. [yangwl:/home/users50/yangwl/test]$ gcc -o ca time.c -O2 -DCA
  31. [yangwl:/home/users50/yangwl/test]$ gcc -o ma time.c -O2 -DMA
  32. [yangwl:/home/users50/yangwl/test]$ ./ca
  33. begin...
  34. 33
  35. [yangwl:/home/users50/yangwl/test]$ ./ma
  36. begin...
  37. 32
  38. [yangwl:/home/users50/yangwl/test]$ ./ca
  39. begin...
  40. 33
  41. [yangwl:/home/users50/yangwl/test]$ ./ma
  42. begin...
  43. 31
  44. [yangwl:/home/users50/yangwl/test]$ ./ca
  45. begin...
  46. 34
  47. [yangwl:/home/users50/yangwl/test]$ ./ma
  48. begin...
  49. 32
  50. [yangwl:/home/users50/yangwl/test]$
复制代码


怕自己因为测的次数少,结果不正确,所以写一个长期测试的程序,下班放在服务器上运行。将结果写入文件,测试代码及结果如下:

  1. [yangwl:/home/users50/yangwl/test]$ cat time.c
  2. #include <stdio.h>;
  3. #include <stdlib.h>;
  4. #include <time.h>;
  5. #include <string.h>;

  6. time_t ma(FILE *);
  7. time_t ca(FILE *);

  8. int main(void) {
  9.         int     i,
  10.                 count = 0,
  11.                 true = 0,
  12.                 false = 0;
  13.         time_t  t,
  14.                 tmp;
  15.         struct tm       *tforp;
  16.         FILE    *fp1,*fp2;

  17.         fp1 = fopen("./log1","w");
  18.         if ( fp1 == NULL ) {
  19.                 printf("log1 open error!\n");
  20.                 exit(1);
  21.         }

  22.         fp2 = fopen("./log2","w");
  23.         if ( fp2 == NULL ) {
  24.                 printf("log2 open error!\n");
  25.                 exit(1);
  26.         }

  27.         t = time(0);
  28.         tforp = localtime(&t);

  29.         fprintf(fp1,"begin time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
  30.                                                      tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);

  31.         fprintf(fp2,"begin time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
  32.                                                      tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);

  33.         for ( i = 0; i < 10*60; i++ ) {
  34.                 tmp = ca(fp2)-ma(fp2);
  35.                 fprintf(fp2," %ld",tmp);
  36.                 tmp >; 0 ? true++ : false++;
  37.                 count++;
  38.         }

  39.         fprintf(fp1,"true:%d\nfalse:%d\ncount:%d\n",true,false,count);

  40.         t = time(0);
  41.         tforp = localtime(&t);

  42.         fprintf(fp1,"end time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
  43.                                                      tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);

  44.         fprintf(fp2,"end time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
  45.                                                      tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);

  46.         fclose(fp1);
  47.         fclose(fp2);

  48.         exit(0);
  49. }

  50. time_t ma(FILE *fp2) {
  51.         int     i;
  52.         char    *p;
  53.         time_t  t;

  54.         t = time(0);
  55.         for ( i = 0; i < 100000000; i++) {
  56.                 p = (char *)malloc(100*sizeof(char));
  57.                 memset(p,0,100);
  58.                 if ( p == NULL ) {
  59.                         fprintf(fp2,"calloc error!\n");
  60.                         exit(1);
  61.                 }
  62.                 free(p);
  63.         }
  64.         t = time(0)-t;

  65.         return t;
  66. }

  67. time_t ca(FILE *fp2) {
  68.         int     i;
  69.         char    *p;
  70.         time_t  t;

  71.         t = time(0);

  72.         for ( i = 0; i < 100000000; i++) {
  73.                 p = (char *)calloc(100,sizeof(char));
  74.                 if ( p == NULL ) {
  75.                         fprintf(fp2,"calloc error!\n");
  76.                         exit(1);
  77.                 }
  78.                 free(p);
  79.         }
  80.         t = time(0)-t;

  81.         return t;
  82. }
  83. [yangwl:/home/users50/yangwl/test]$ cat log1
  84. begin time:104-8-8 19:19:22
  85. true:586
  86. false:14
  87. count:600
  88. end time:70-0-1 21:1:21
  89. [yangwl:/home/users50/yangwl/test]$ cat log2
  90. begin time:104-8-8 19:19:22
  91. 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 1 2 1 2 1 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1end time:70-0-1 21:1:21
  92. [yangwl:/home/users50/yangwl/test]$
复制代码


结果:果然calloc函数的效率要稍微低一点,平均差2sec,少数差1sec,极少可以做到几乎不差。要注意,结果只能精确到sec。

猜想原因:有一个很明显的能看出来的差别是,calloc函数要在函数运行中计算总共开辟多大空间。而malloc函数的参数只有一个,在上面的程序钟,这个参数是一个可以在编译的过程中就确定大小的表达式,因此能事先确定开辟空间的大小。但是,性能的差别仅仅在于一个乘法操作吗?

bug:呵呵,大家可以看出来,log文件中的日期时间有问题。是因为忘记了localtime的用法,以及取时间语句的一个错误,昨天着急写程序所致,不过并不影响结果。

意外:本来一次循环应该耗时1分多钟,所以我定了600次循环,本来以为可以让它运行一晚上,结果看log,2个小时不到就结束了,不知道为什么,是服务器在晚上的运算速度提高了?还是经常性的“分配”“释放”,系统的内存管理机制习惯了这样的动作导致“熟能生巧”了?[/code]

论坛徽章:
0
2 [报告]
发表于 2004-09-09 10:14 |只看该作者

calloc函数的效率

...而malloc函数可以在编译的过程中就确定开辟空间的大小。

不是这样的.

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
3 [报告]
发表于 2004-09-09 10:23 |只看该作者

calloc函数的效率

原帖由 "JohnBull" 发表:

不是这样的.


怎么不是呢?

calloc(100,sizeof(char))是一定要做一个100*sizeof(char)的动作的,而
malloc(100*sizeof(char))里面,不是可以在编译的时候就确定sizeof的值,而且将100*1这样的算式直接优化成100这个值吗?好像编译器都有这样的优化吧?

论坛徽章:
0
4 [报告]
发表于 2004-09-09 10:23 |只看该作者

calloc函数的效率

>;>; 系统的内存管理机制习惯了这样的动作导致“熟能生巧”了

我来帮你解释吧。

因为局部引用的特性 和 cpu的高速缓存的作用。它高速缓存了指令和数据,如果命中都是在一级缓存的话,该缓存的速度和cpu是一样的,如果是二级缓存命中的话,二级缓存速度是cpu的一半。不管怎么样,还是比没有缓存命中的速度高很多。经过长时间运行,高速缓存算法淘汰了其他进程的缓存,可以认为,长时间运行时,缓存的都是这个进程的数据和代码。

也可能还有mmu的TLB寄存器起作用,开始访问数据和代码的时候是需要经过mmu进行虚拟地址到物理地址的转换,运行一段时间以后,这些地址已经保存在了TLB里面,它也是和cpu等速度的。一旦高速缓存中没有命中,也不需要付出地址变换的代价。

还有就是存储器替换算法的作用,因为开始运行的时候,内存中的进程比较多,一次分配大存储空间是需要较长时间查找,因为可能有内存碎片,如果还没有找到你需要的大空间的话,OS会选择替换内存数据,直到找到符合请求的内存。

而长时间运行后,一些进程OS会将他交换出物理内存,这样的话,就可以组成更大的空闲空间,os在进行内存分配请求的时候就不需要花很多时间来进行查找。

所以“熟能生巧”

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
5 [报告]
发表于 2004-09-09 10:36 |只看该作者

calloc函数的效率

[quote]原帖由 "ljttlf"]是的,因为局部引用的特性 和 cpu的高速缓存的作用。它高速缓存了指令和数据,如果命中都是在一级缓存的话,该缓存的速度和cpu是一样的,如果是二级缓存命中的话,二级缓存速度是cpu的一半。不管怎么样,还是比没有?.........[/quote 发表:


^_^,对,对,就是这样,偶想的不深入,谢谢ljttlf兄了,上学学的东西全忘了。

论坛徽章:
0
6 [报告]
发表于 2004-09-09 10:45 |只看该作者

calloc函数的效率

呵呵,大家学习

论坛徽章:
0
7 [报告]
发表于 2004-09-09 11:37 |只看该作者

calloc函数的效率

看了ljttlf的解释,对为什么总体运行时间少了有了一点认识。
可是,关于为什么calloc没有melloc+memset快还是没有解开,继续聆听,期待中……

论坛徽章:
0
8 [报告]
发表于 2004-09-09 12:06 |只看该作者

calloc函数的效率

[quote]原帖由 "aero" 发表:


怎么不是呢?

calloc(100,sizeof(char))是一定要做一个100*sizeof(char)的动作的,而
malloc(100*sizeof(char))里面,不是可以在编译的时候就确定sizeof的值,而且将100*1这样的算式直接优化成100这个值吗?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
9 [报告]
发表于 2004-09-09 12:11 |只看该作者

calloc函数的效率

呵呵,谢谢JohnBull老大。自己表述的有问题呢。^_^。改过来了。

论坛徽章:
0
10 [报告]
发表于 2004-09-09 12:25 |只看该作者

calloc函数的效率

没有乘法操作。
100*sizeof(char)是个常数=100,在编译时就确定。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP