函数调用:即调用函数调用被调用函数,调用函数压栈,被调用函数执行,调用函数出栈,调用函数继续执行的一个看似简单的过程,系统底层却做了大量操作。

操作:

1,               调用函数帧指针(函数参数,局部变量,栈帧状态值,函数返回地址)入栈,栈指针自减

2,               保存调用函数的状态数据入寄存器

3,               被调用函数帧指针入栈,执行当前的被调用函数

4,               被调用函数执行结束,退栈,返回到调用函数的帧指针,从寄存器中恢复当时状态数据

5,               继续执行调用函数,直至结束

即整个调用操作有一个压栈出栈,保存和恢复状态数据的过程。而系统栈内存是有默认的固有大小。有多少次函数调用就会分配多少栈帧。故,函数调用性能影响有如下因素:

1,函数递归层数;

2,参数个数(参数签名所占内存大小)

2.1同类型不同参数个数;

2.2同参数个数不同参数类型;

2.3同参数类型同参数个数,但参数类型所占内存大小不同;

3,函数栈大小,即函数局部变量所占栈大小。

为了测试C语言函数调用性能(时间消耗)因素,编写了一个简单程序运行在如下环境中:

Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz  memery size:7833700 kB(7.47GB)

在函数调用的开始与结束处,用time.h中的clock()函数返回CPU时钟计时单位数(下表中的starttime和endtime),用durationtime=endtime-starttime表示函数调用的时间消耗。如下:

clock_t  starttime=clock();

函数调用…

clock_t  endtime=clock();

//除以CLOCKS_PER_SEC,得到以秒为单位的时间结果

double durationtime=(double)(endtime-starttime)/CLOCKS_PER_SEC;//表示函数调用占用cpu的时间,不包括子进程或者printf等的操作的时间

注:clock()记录的是进程占用cpu的时间,精确度为微秒;详细讲解clock()函数的网址:http://site.douban.com/199048/widget/notes/12005386/note/253542964/

一.函数递归层数(循环1000000次)

栈(字节)

参数(字节)

递归次数

总函数调用时间消耗(秒)

每循环函数调用时间消耗(微秒)

每次函数调用平均时间消耗(纳秒)

1024

24

10

2.9

2.9

290

1024

24

20

5.713

5.713

285.65

1024

24

30

9.025

9.025

300.83

1024

24

50

16.0767

16.0767

321.534

1024

24

80

21.79

21.79

272.375

1024

24

100

30.73

30.73

307.3

1024

24

200

66.24

66.24

331.2

注:平均每次函数调用时间消耗=durationtime/调用层数/ 循环次数

每循环函数调用时间消耗=durationtime/ 循环次数

函数调用根据不同的调用层数不同的时间平均消耗,如下折线图:

图1

每次函数调用平均时间消耗,如下折线图:

图2

结论:1,在参数所占内存相同和函数栈大小相同的情况下,函数调用的时间消耗随着函数调用层数增加而增加;如图1;

2,在参数所占内存相同和函数栈大小相同的情况下,每次函数调用的时间消耗大概在300纳秒左右;如图2;

二,函数栈大小

循环次数

栈(字节)

参数

(字节)

递归次数

总函数调用时间消耗(秒)

每循环函数调用时间消耗(微秒)

平均每次函数调用(纳秒)

1000000

16

24

50

9.4

9.4

184

1000000

32

24

50

9.37

9.37

187.4

1000000

64

24

50

9.5

9.5

190

1000000

128

24

50

10.415

10.415

208.3

1000000

256

24

50

11.805

11.805

236.1

1000000

512

24

50

14

14

280

1000000

1024

24

50

16.0767

16.0767

321.534

1000000

2048

24

50

18.42

18.42

368.4

注:平均每次函数调用时间消耗=durationtime/调用层数/ 循环次数

每循环函数调用时间消耗=durationtime/ 循环次数

函数调用根据不同的调用层数不同的时间平均消耗,如下折线图:

图3

每次函数调用平均时间消耗,如下折线图:

图4

结论:1,在函数参数相同和函数调用层数相同的情况下,函数调用时间消耗随函数栈大小的增加而增加;如图3;

2,在函数参数相同和函数调用层数相同的情况下,每次函数调用时间消耗随函数栈大小的增加而增加;如图4;

三,参数个数

栈(字节)

参数

(字节)

递归次数

总函数调用时间消耗(秒)

每循环函数调用时间消耗(微秒)

平均每次函数调用(纳秒)

1024

24

50

16.0767

16.0767

321.5

1024

36

50

16.245

16.245

324.9

1024

48

50

16.345

16.345

326.9

1024

60

50

15.915

15.915

318.3

1024

72

50

14.29

14.29

285.8

1024

84

50

15.76

15.76

315.2

1024

96

50

15.14

15.14

302.8

1024

108

50

13.975

13.975

279.5

1024

120

50

16.68

16.68

333.6

1024

144

50

15.37

15.37

307.4

1024

180

50

14.42

14.42

288.4

1024

192

50

14.62

14.62

292.4

注:平均每次函数调用时间消耗=durationtime/调用层数/ 循环次数

每循环函数调用时间消耗=durationtime/ 循环次数

函数调用根据不同的函数参数大小的时间平均消耗,如下折线图:

每次函数调用平均时间消耗,如下折线图:

结论:  经过前几次的函数测试,虽然存在误差,但是仍然可以得出参数对于函数调用的时间消耗的影响,在于参数所占内存大小;函数传参存在两种方式:值传参和引用传参;两种方式在一般情况下,不会占用过多的内存;故,在一般情况下,参数对函数调用的时间消耗的影响不明显;

四,结论:

1,在函数参数大小为24字节和函数栈大小为1024字节的情况下,递归50次的函数时间消耗为16.0767微秒,可以粗略得出每次函数调用(压栈出栈)的时间消耗为320纳秒左右;

思路:1,函数参数大小:函数参数分为值传参和引用传参(参数的指针);一般值传参为常用的值类型,这样的参数一般不会占用过多的内存;引用参数是参数地址也不会占用过多内存;所以在一般情况下,函数参数对函数调用时间消耗影响不大;

2,计数:循环1000000次函数递归,是为了想提高数据的精确性和便于计算;1秒=1000000微秒;

3,递归层数:选择可能常规下递归的层数(24--35)

4,函数栈大小:按照以太网的最大字节1500字节,选择在1024字节左右做以上实验;

代码:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define array_len 256
typedef struct {
int typeone;
int typetwo;
}struct_type;
long call_back(int call_num,int typeone,int typetwo,int typethree,long p_recorde)
{
if(call_num<=)return p_recorde;
int i_rand[array_len];
int i=;
clock_t start_time,end_time;
start_time=clock();
for(i=;i<array_len;i++)
{
i_rand[i]=rand();
}
end_time=clock();
p_recorde+=(long)(end_time-start_time);
call_back(call_num-,typeone,typetwo,typethree,p_recorde);
}
void main(int argc,char *argv[])
{
int loop_num=atoi(argv[]),call_num=atoi(argv[]);
long p_recorde=,sum=;
clock_t start_time,end_time;
start_time=clock();
int i;
for(i=;i<loop_num;i++)
{
sum_loop+=call_back(call_num,,,,p_recorde);
}
end_time=clock();
double duration_time=(double)(end_time-start_time)/CLOCKS_PER_SEC-(double)sum_loop/CLOCKS_PER_SEC;
printf("sum=%f duration=%f\n",sum_loop,duration_time);
}

代码思路:1,为了减少数据cache命中的影响,在每次函数调用中用了rand()获取随机数,并记录时间消耗a;

2,记录函数调用的时间总消耗b,b-a的差即为函数调用的时间总消耗;

测试c语言函数调用性能因素之测试三的更多相关文章

  1. 进行app性能和安全性测试的重要性

    如何让用户感觉App运行速度更快呢,这需要对App进行性能测试.限制App性能的因素按照App的系统结构分为App自身和App需要用到的后台服务. 测试App连接网络的速度 一般采用在模拟Mock环境 ...

  2. 入门级----黑盒测试、白盒测试、手工测试、自动化测试、探索性测试、单元测试、性能测试、数据库性能、压力测试、安全性测试、SQL注入、缓冲区溢出、环境测试

    黑盒测试 黑盒测试把产品软件当成是一个黑箱子,只有出口和入口,测试过程中只要知道往黑盒中输入什么东西,知道黑盒会出来什么结果就可以了,不需要了解黑箱子里面是如果做的. 即测试人员不用费神去理解软件里面 ...

  3. 集群搭建完成简要测试集群(性能)带宽与IOPS

    集群搭建好之后网络,raid卡策略,磁盘都会影响集群的性能.为了避免因上述问题使得集群的性能受到影响,我们依次进行测试,最后得到基本的集群性能. 网络 首先是网络,ceph集群一大堆让人摸不着头脑的问 ...

  4. Linux 性能监控、测试、优化工具

    Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...

  5. 三张图看遍Linux 性能监控、测试、优化工具

    Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...

  6. (太强大了) - Linux 性能监控、测试、优化工具

    转: http://www.vpsee.com/2014/09/linux-performance-tools/ Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经 ...

  7. Web 应用性能和压力测试工具 Gor - 运维生存时间

    Web 应用性能和压力测试工具 Gor - 运维生存时间 undefined 无需花生壳,dnspod实现ddns - 推酷 undefined

  8. [转载]Linux 性能监控、测试、优化工具

    Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...

  9. Webbench、ab命令:做压力测试的工具和性能的监控工具

    DDOS攻击:???DDOS概述:分布式拒绝服务(DDoS:Distributed Denial of Service)攻击,指借助于客户/服务器技术,将多个计算机联合起来作为攻击平台,对一个或多个目 ...

随机推荐

  1. 开机一会,出现长时间闪屏,并且跳出SendRpt error

    通过谷歌,发现任务管理器中的Report sending utility 是属于TortoiseSVN 的,所以卸载svn ,然后重启就ok了

  2. 中兴软件编程规范C/C++

    Q/ZX 深圳市中兴通讯股份有限公司企业标准 (设计技术标准) Q/ZX 04.302.1–2003      软件编程规范C/C++                               20 ...

  3. html中调用silverlight中的方法

    在xaml页面中放置一个textblock控件来绑定数据 <ItemsControl   x:Name="cityname">            <Items ...

  4. django笔记

    apt-get install libmysqlclient-devpip install mysqlclientsudo apt-get install libxml2-dev libxslt1-d ...

  5. Java通过SpyMemcached来缓存数据

    配置好Magent+memcached后,很明显数据之间的输入与输出都是通过代理服务器的,magent是做代理服务器的很明显java在memecached的调用驱动在magent同样适用. 这里选择S ...

  6. golang没有条件表达式?:

    详见The Go Programming Language Specification中Expressions一章中未提及此表达式, 故其不支持. 再强调一次, GO不支持条件表达式 conditio ...

  7. HTML5七大优势“逼宫”APP

    HTML5颠覆了PC互联网的格局,优化了移动互联网的体验,接下来几年,HTML5将颠覆原生App世界. 跨平台: 在多屏年代,开发者的痛苦指数非常高,人人都期盼HTML5能扮演救星.多套代码.不同技术 ...

  8. C#泛型集合之Dictionary<k, v>使用技巧

    1.要使用Dictionary集合,需要导入C#泛型命名空间 System.Collections.Generic(程序集:mscorlib) 2.描述 1).从一组键(Key)到一组值(Value) ...

  9. c++中头文件include规则浅析[译]

    英文原文地址 在开发大型的软件项目时,头文件需要得到恰当的管理,甚至在c中也会面临这种问题,当我们用c++开发时,头文件的管理会变得更复杂,更加耗费我们的时间去管理,下面我将讲一些包含规则来简化这个苦 ...

  10. LeetCode-Data Stream as Disjoint Intervals

    Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen ...