测试c语言函数调用性能因素之测试三
函数调用:即调用函数调用被调用函数,调用函数压栈,被调用函数执行,调用函数出栈,调用函数继续执行的一个看似简单的过程,系统底层却做了大量操作。
操作:
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语言函数调用性能因素之测试三的更多相关文章
- 进行app性能和安全性测试的重要性
如何让用户感觉App运行速度更快呢,这需要对App进行性能测试.限制App性能的因素按照App的系统结构分为App自身和App需要用到的后台服务. 测试App连接网络的速度 一般采用在模拟Mock环境 ...
- 入门级----黑盒测试、白盒测试、手工测试、自动化测试、探索性测试、单元测试、性能测试、数据库性能、压力测试、安全性测试、SQL注入、缓冲区溢出、环境测试
黑盒测试 黑盒测试把产品软件当成是一个黑箱子,只有出口和入口,测试过程中只要知道往黑盒中输入什么东西,知道黑盒会出来什么结果就可以了,不需要了解黑箱子里面是如果做的. 即测试人员不用费神去理解软件里面 ...
- 集群搭建完成简要测试集群(性能)带宽与IOPS
集群搭建好之后网络,raid卡策略,磁盘都会影响集群的性能.为了避免因上述问题使得集群的性能受到影响,我们依次进行测试,最后得到基本的集群性能. 网络 首先是网络,ceph集群一大堆让人摸不着头脑的问 ...
- Linux 性能监控、测试、优化工具
Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...
- 三张图看遍Linux 性能监控、测试、优化工具
Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...
- (太强大了) - Linux 性能监控、测试、优化工具
转: http://www.vpsee.com/2014/09/linux-performance-tools/ Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经 ...
- Web 应用性能和压力测试工具 Gor - 运维生存时间
Web 应用性能和压力测试工具 Gor - 运维生存时间 undefined 无需花生壳,dnspod实现ddns - 推酷 undefined
- [转载]Linux 性能监控、测试、优化工具
Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...
- Webbench、ab命令:做压力测试的工具和性能的监控工具
DDOS攻击:???DDOS概述:分布式拒绝服务(DDoS:Distributed Denial of Service)攻击,指借助于客户/服务器技术,将多个计算机联合起来作为攻击平台,对一个或多个目 ...
随机推荐
- 1.python的第一步
学习python也有一段时间了,自认为基本算是入门了,想要写一些博客进行知识的汇总的时候.却发现不知道该从何说起了,因为python这门语言在语法上其实并不难,关键在于如何建立程序员的思维方式,而对于 ...
- SQL基础知识----数据类型
VARCHAR(VERiable CHARacter):可变动字符.用于保存以文本格式处处的信息,最大可以储存255个字符.一般使用为VAECHAR(10) --表示最多可以存储10个字符 INT ...
- .Net码农学Android---快速了解数据存储
数据存储 Andoid中的数据存储和我们平时见到的不一样,或者说移动设备的存储和平时不一样.Andoid中的存储方式有五种, 单把存储拎出来,是因为我们后续的开发会经常用到,重要性不言而喻,多样的存储 ...
- ListView的动态刷新问题——用notifyDataSetChanged没作用
也许很多开发的朋友,尤其是Android初学者(笔者也是个初学者),在动态刷新ListView时,使用notifyDataSetChanged并没有起到作用.有时会被困扰得很痛苦. 其实,在使用not ...
- hdu 1427 速算24点
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1427 速算24点 Description 速算24点相信绝大多数人都玩过.就是随机给你四张牌,包括A( ...
- hdu 1303 Doubles
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1303 Doubles Description As part of an arithmetic com ...
- Get 和 Post方法的登录
1. Get & Post 1> Get请求直接从服务器拿数据 性能好 效率高 在地址栏会显示所有的参数,从直观上安全性不高 由于Get不提交数据给服务器,因此实际的安全性高 实际应用: ...
- Socket与TcpClient的区别(转载)
Socket和TcpClient有什么区别 原文:http://wxwinter.spaces.live.com/blog/cns!C36588978AFC344A!322.entry 回答: &qu ...
- Apple Watch应用开发经验谈:我遇到的那些坑
本文作者张忠良是滴答清单Apple Watch版应用的开发工程师,他用了一周的时间使用纯Objective-C语言完成了Apple Watch版滴答清单应用的开发工作.在这里,他从开发角度阐述了个人对 ...
- Beyond Compare 4
Beyond Compare是一款不可多得的专业级的文件夹和文件对比工具.使用他可以很方便的对比出两个文件夹或者文件的不同之处.并把相差的每一个字节用颜色加以表示,查看方便.并且支持多种规则对比.