C++ 函数调用时间开销

1.前言

         调用函数的开销大致可分两个部分:传递参数的开销和保存当前程序上下文信息所花费的开销。对于传递参数的开销而言,传递的参数越多开销就越大;对于保存当前程序上下文所花费的开销而言,函数越复杂需要花费的开销就越大。

2.函数调用约定

         函数调用约定,是指当一个函数被调用时,函数的参数会被传递给被调用的函数和返回值会被 返回给调用函数。函数的调用约定就是描述参数是怎么传递和由谁平衡堆栈的,当然还有返回值。

  • __stdcall
    (1)堆栈平衡是由调用函数来执行

  • __cdecl
    (1)堆栈平衡操作是由被调用函数执行的

  • __fastcall
    (1)参数应该放在寄存器中,而不是在栈中,最左边的两个不大于4个字节(DWORD)的参数分别放在ecx和edx寄存器。当寄存器用完的时候,其余参数仍然从右到左的顺序压入堆栈。像浮点值、远指针和__int64类型总是通过堆栈来传递的。

  • __thiscall
    (1)会使用一个寄存器或在函数中添加一个不可见的参数来传递类指针

  • __pascal
    (1)参数从左到右依次入栈

  • __nakedcall
    (1)编译器不会生成 prolog 和 epilog 代码

  • __vectorcall
    (1)使用的参数寄存器多于__fastcall或默认的x64调用约定,可传递三种参数:整数类型值,矢量类型值和同构向量聚合(HVA)值。

  //  HVA类型是最多四个具有相同矢量类型的数据成员的复合类型。
  //  HVA类型与其成员的向量类型具有相同的对齐要求。
  //  这是一个包含三个相同矢量类型并具有32字节对齐的HVA 结构定义的示例:
typedef struct {
  __m256 x;
  __m256 y;
  __m256 z;
} hva3;

3.函数类型

3.1.普通函数

形如:

auto [__stdcall,__cdecl] add(int par1,int par2){
	return par1+par2;
}

         当然,C++ 默认调用方式为__cdecl 即便你什么都不写,其中__cdecl 可以有可变参数 例如 : int add(int a, …);

3.2.模板函数

形如:

template<class _Ty>
auto add(_Ty par1,_Ty par2){
	return par1+par2;
}

         模板函数在实例化之后效率是和普通函数一样的,如:

auto v = add(1,2);

         对应的实例化版本:

template<int>
auto add(int par1,int par2){
	return par1+par2;
}

         与3.1的add函数一致

3.3 内联函数

         内联扩展是一种特别的用于消除调用函数时所造成的固有的时间消耗方法。一般用于能够快速执行的函数,因为在这种情况下函数调用的时间消耗显得更为突出。这种方法对于很小的函数也有空间上的益处,并且它也使得一些其他的优化成为可能。
形如:

inline auto add(int par1,int par2){
	return par1+par2;
}

会直接在调用方展开(如果编译器也认为展开更合适)

// 此时如下调用
auto v = add(1,2);
// 生成的汇编会类似
auto v = 1 + 2;

3.4 宏函数

形如:

#define _ADD(a,b) ((a)+(b))

auto v = _ADD(1,2);
// 实际宏展开后
auto v = ((1)+(2));
// 去除多余括号
auto v = 1 + 2;

3.4 虚函数

         在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
形如:

class A {
public:
	virtual auto virtual_func(void) { return 0.0; }
	float mem = 0.0;
};

class B :public A {
public:
	virtual auto virtual_func(void){return 1.0;}
};

// 作如下调用
A* obj = new B;
auto v = obj->virtual_func();
// v 为 1.0

         虚函数因为调用机制(进行查表寻址),一般是不会被编译器优化为内联函数(如果确实可以确定被调用的函数,如 B b; b.virtual_func(); 如果函数适合内联则内联,那么就会经行内联)

4.函数调用开销测试

因为宏函数的特殊性,不做测试,将其结果视为等同确定内联展开的内联函数开销。

本次测试函数基准,进行大量迭代,其中value 初始值为0.0:

// 调用基准
value += normal_func(0.3, 0.2, 0.7, value);

// 基准函数
double normal_func(float x, float y, float z, float w) {
	auto ret = -x * w - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * w - x * y + z * w;
	return ret / 100.0;
}

// 针对虚函数__thiscall 做出了一些平衡
class A {
public:
	virtual double virtual_func(double x, double y, double z) { return 0.0; }
	double mem = 0.0;
};

class B :public A {
public:
	virtual double virtual_func(double x, double y, double z);
};
// 调用方式 value += obj->virtual_func(0.3, 0.2, 0.7);
// 但在最后 value = obj->mem;
double B::virtual_func(double x, double y, double z) {
	double ret = -x * mem - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * mem - x * y + z * mem;
	ret ;
	return mem += (ret/ 100.0);
}

总的代码清单请见附页

为了确认调用方式,下面是Release64模式下汇编代码

		// 普通函数调用
		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += normal_func(0.3, 0.2, 0.7, value);
00007FF714EA11F0  movaps      xmm3,xmm6   // 这里被优化为寄存器传递
00007FF714EA11F3  movaps      xmm2,xmm7  
00007FF714EA11F6  movaps      xmm1,xmm8  
00007FF714EA11FA  movaps      xmm0,xmm9  
00007FF714EA11FE  call        normal_func (07FF714EA1030h) 
00007FF714EA1203  addsd       xmm6,xmm0  
00007FF714EA1207  sub         rax,1  
00007FF714EA120B  jne         main+130h (07FF714EA11F0h)  
		}
		// 内联函数调用
		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += inline_func(0.3, 0.2, 0.7, value);
00007FF714EA1262  movaps      xmm2,xmm6  
00007FF714EA1265  movaps      xmm1,xmm6  
00007FF714EA1268  mulsd       xmm2,xmm14  
00007FF714EA126D  movaps      xmm0,xmm6  
00007FF714EA1270  mulsd       xmm1,xmm8  
00007FF714EA1275  mulsd       xmm0,xmm7  
00007FF714EA1279  subsd       xmm2,xmm12  
00007FF714EA127E  subsd       xmm1,xmm4  
00007FF714EA1282  subsd       xmm2,xmm15  
00007FF714EA1287  addsd       xmm1,xmm0  
00007FF714EA128B  mulsd       xmm2,xmm9  
00007FF714EA1290  subsd       xmm2,xmm12  
00007FF714EA1295  xorps       xmm2,xmm13  
00007FF714EA1299  divsd       xmm2,xmm1  
00007FF714EA129D  divsd       xmm2,xmm5  
00007FF714EA12A1  addsd       xmm6,xmm2  
00007FF714EA12A5  movaps      xmm3,xmm6  
00007FF714EA12A8  movaps      xmm1,xmm6  
00007FF714EA12AB  mulsd       xmm3,xmm14  
00007FF714EA12B0  movaps      xmm0,xmm6  
00007FF714EA12B3  mulsd       xmm1,xmm8  
00007FF714EA12B8  mulsd       xmm0,xmm7  
00007FF714EA12BC  subsd       xmm3,xmm12  
00007FF714EA12C1  subsd       xmm1,xmm4  
00007FF714EA12C5  subsd       xmm3,xmm15  
00007FF714EA12CA  addsd       xmm1,xmm0  
00007FF714EA12CE  mulsd       xmm3,xmm9  
00007FF714EA12D3  subsd       xmm3,xmm12  
00007FF714EA12D8  xorps       xmm3,xmm13  
00007FF714EA12DC  divsd       xmm3,xmm1  
00007FF714EA12E0  divsd       xmm3,xmm5  
00007FF714EA12E4  addsd       xmm6,xmm3  
00007FF714EA12E8  movaps      xmm2,xmm6  
00007FF714EA12EB  movaps      xmm1,xmm6  
00007FF714EA12EE  mulsd       xmm2,xmm14  
00007FF714EA12F3  movaps      xmm0,xmm6  
00007FF714EA12F6  mulsd       xmm1,xmm8  
00007FF714EA12FB  mulsd       xmm0,xmm7  
00007FF714EA12FF  subsd       xmm2,xmm12  
00007FF714EA1304  subsd       xmm1,xmm4  
00007FF714EA1308  subsd       xmm2,xmm15  
00007FF714EA130D  addsd       xmm1,xmm0  
00007FF714EA1311  mulsd       xmm2,xmm9  
00007FF714EA1316  subsd       xmm2,xmm12  
00007FF714EA131B  xorps       xmm2,xmm13  
00007FF714EA131F  divsd       xmm2,xmm1  
00007FF714EA1323  divsd       xmm2,xmm5  
00007FF714EA1327  addsd       xmm6,xmm2  
00007FF714EA132B  movaps      xmm3,xmm6  
00007FF714EA132E  movaps      xmm1,xmm6  
00007FF714EA1331  mulsd       xmm3,xmm14  
00007FF714EA1336  movaps      xmm0,xmm6  
00007FF714EA1339  mulsd       xmm1,xmm8  
00007FF714EA133E  mulsd       xmm0,xmm7  
00007FF714EA1342  subsd       xmm3,xmm12  
00007FF714EA1347  subsd       xmm1,xmm4  
00007FF714EA134B  subsd       xmm3,xmm15  
00007FF714EA1350  addsd       xmm1,xmm0  
00007FF714EA1354  mulsd       xmm3,xmm9  
00007FF714EA1359  subsd       xmm3,xmm12  
00007FF714EA135E  xorps       xmm3,xmm13  
00007FF714EA1362  divsd       xmm3,xmm1  
00007FF714EA1366  divsd       xmm3,xmm5  
00007FF714EA136A  addsd       xmm6,xmm3  
00007FF714EA136E  movaps      xmm2,xmm6  
00007FF714EA1371  movaps      xmm1,xmm6  
00007FF714EA1374  mulsd       xmm2,xmm14  
00007FF714EA1379  movaps      xmm0,xmm6  
00007FF714EA137C  mulsd       xmm1,xmm8  
00007FF714EA1381  mulsd       xmm0,xmm7  
00007FF714EA1385  subsd       xmm2,xmm12  
00007FF714EA138A  subsd       xmm1,xmm4  
00007FF714EA138E  subsd       xmm2,xmm15  
00007FF714EA1393  addsd       xmm1,xmm0  
00007FF714EA1397  mulsd       xmm2,xmm9  
00007FF714EA139C  subsd       xmm2,xmm12  
00007FF714EA13A1  xorps       xmm2,xmm13  
00007FF714EA13A5  divsd       xmm2,xmm1  
00007FF714EA13A9  divsd       xmm2,xmm5  
00007FF714EA13AD  addsd       xmm6,xmm2  
00007FF714EA13B1  movaps      xmm3,xmm6  
00007FF714EA13B4  mulsd       xmm3,xmm14  
00007FF714EA13B9  movaps      xmm1,xmm6  
00007FF714EA13BC  mulsd       xmm1,xmm8  
00007FF714EA13C1  movaps      xmm0,xmm6  
00007FF714EA13C4  mulsd       xmm0,xmm7  
00007FF714EA13C8  subsd       xmm3,xmm12  
00007FF714EA13CD  subsd       xmm1,xmm4  
00007FF714EA13D1  subsd       xmm3,xmm15  
00007FF714EA13D6  addsd       xmm1,xmm0  
00007FF714EA13DA  mulsd       xmm3,xmm9  
00007FF714EA13DF  subsd       xmm3,xmm12  
00007FF714EA13E4  xorps       xmm3,xmm13  
00007FF714EA13E8  divsd       xmm3,xmm1  
00007FF714EA13EC  divsd       xmm3,xmm5  
00007FF714EA13F0  addsd       xmm6,xmm3  
00007FF714EA13F4  movaps      xmm2,xmm6  
00007FF714EA13F7  movaps      xmm1,xmm6  
00007FF714EA13FA  mulsd       xmm2,xmm14  
00007FF714EA13FF  movaps      xmm0,xmm6  
00007FF714EA1402  mulsd       xmm1,xmm8  
00007FF714EA1407  mulsd       xmm0,xmm7  
00007FF714EA140B  subsd       xmm2,xmm12  
00007FF714EA1410  subsd       xmm1,xmm4  
00007FF714EA1414  subsd       xmm2,xmm15  
00007FF714EA1419  addsd       xmm1,xmm0  
00007FF714EA141D  mulsd       xmm2,xmm9  
00007FF714EA1422  subsd       xmm2,xmm12  
00007FF714EA1427  xorps       xmm2,xmm13  
00007FF714EA142B  divsd       xmm2,xmm1  
00007FF714EA142F  divsd       xmm2,xmm5  
00007FF714EA1433  addsd       xmm6,xmm2  
00007FF714EA1437  movaps      xmm3,xmm6  
00007FF714EA143A  movaps      xmm1,xmm6  
00007FF714EA143D  mulsd       xmm3,xmm14  
00007FF714EA1442  movaps      xmm0,xmm6  
00007FF714EA1445  mulsd       xmm1,xmm8  
00007FF714EA144A  mulsd       xmm0,xmm7  
00007FF714EA144E  subsd       xmm3,xmm12  
00007FF714EA1453  subsd       xmm1,xmm4  
00007FF714EA1457  subsd       xmm3,xmm15  
00007FF714EA145C  addsd       xmm1,xmm0  
00007FF714EA1460  mulsd       xmm3,xmm9  
00007FF714EA1465  subsd       xmm3,xmm12  

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += inline_func(0.3, 0.2, 0.7, value);
00007FF714EA146A  xorps       xmm3,xmm13  
00007FF714EA146E  divsd       xmm3,xmm1  
00007FF714EA1472  divsd       xmm3,xmm5  
00007FF714EA1476  addsd       xmm6,xmm3  
00007FF714EA147A  movaps      xmm1,xmm6  
00007FF714EA147D  movaps      xmm0,xmm6  
00007FF714EA1480  mulsd       xmm1,xmm8  
00007FF714EA1485  movaps      xmm2,xmm6  
00007FF714EA1488  mulsd       xmm2,xmm14  
00007FF714EA148D  mulsd       xmm0,xmm7  
00007FF714EA1491  subsd       xmm1,xmm4  
00007FF714EA1495  subsd       xmm2,xmm12  
00007FF714EA149A  addsd       xmm1,xmm0  
00007FF714EA149E  subsd       xmm2,xmm15  
00007FF714EA14A3  mulsd       xmm2,xmm9  
00007FF714EA14A8  subsd       xmm2,xmm12  
00007FF714EA14AD  xorps       xmm2,xmm13  
00007FF714EA14B1  divsd       xmm2,xmm1  
00007FF714EA14B5  divsd       xmm2,xmm5  
00007FF714EA14B9  addsd       xmm6,xmm2  
00007FF714EA14BD  movaps      xmm3,xmm6  
00007FF714EA14C0  movaps      xmm1,xmm6  
00007FF714EA14C3  mulsd       xmm3,xmm14  
00007FF714EA14C8  movaps      xmm0,xmm6  
00007FF714EA14CB  mulsd       xmm1,xmm8  
00007FF714EA14D0  mulsd       xmm0,xmm7  
00007FF714EA14D4  subsd       xmm3,xmm12  
00007FF714EA14D9  subsd       xmm1,xmm4  
00007FF714EA14DD  subsd       xmm3,xmm15  
00007FF714EA14E2  addsd       xmm1,xmm0  
00007FF714EA14E6  mulsd       xmm3,xmm9  
00007FF714EA14EB  subsd       xmm3,xmm12  
00007FF714EA14F0  xorps       xmm3,xmm13  
00007FF714EA14F4  divsd       xmm3,xmm1  
00007FF714EA14F8  divsd       xmm3,xmm5  
00007FF714EA14FC  addsd       xmm6,xmm3  
00007FF714EA1500  sub         rax,1  
00007FF714EA1504  jne         main+1A2h (07FF714EA1262h)  
		}
		// __fastcall调用
		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += fast_func(0.3, 0.2, 0.7, value);
00007FF714EA1550  movaps      xmm3,xmm6  
00007FF714EA1553  movaps      xmm2,xmm7  
00007FF714EA1556  movaps      xmm1,xmm8  
00007FF714EA155A  movaps      xmm0,xmm9  
00007FF714EA155E  call        normal_func (07FF714EA1030h)  // 这里被优化为normal_func
00007FF714EA1563  addsd       xmm6,xmm0  
00007FF714EA1567  sub         rax,1  
00007FF714EA156B  jne         main+490h (07FF714EA1550h)  
		}
		// 虚函数调用
		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += obj->virtual_func(0.3, 0.2, 0.7);
00007FF714EA15C0  mov         rcx,qword ptr [obj (07FF714EA5700h)]  

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += obj->virtual_func(0.3, 0.2, 0.7);
00007FF714EA15C7  movaps      xmm3,xmm7  
00007FF714EA15CA  movaps      xmm2,xmm8  
00007FF714EA15CE  movaps      xmm1,xmm9  
00007FF714EA15D2  mov         rax,qword ptr [rcx]  
00007FF714EA15D5  call        qword ptr [rax]  
00007FF714EA15D7  sub         rdi,1  
00007FF714EA15DB  jne         main+500h (07FF714EA15C0h)  
		}
		// __vectorcall 
		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += vector_func(0.3, 0.2, 0.7, value);
00007FF714EA1630  movaps      xmm3,xmm6  
00007FF714EA1633  movaps      xmm2,xmm7  
00007FF714EA1636  movaps      xmm1,xmm8  
00007FF714EA163A  movaps      xmm0,xmm9  
00007FF714EA163E  call        normal_func (07FF714EA1030h)  // 这里被优化为normal_func
00007FF714EA1643  addsd       xmm6,xmm0  
00007FF714EA1647  sub         rax,1  
00007FF714EA164B  jne         main+570h (07FF714EA1630h)  
		}

第一次测试结果:

组名测试组1测试组2测试组 3测试组 4测试组 5测试组 6测试组 7测试组 8测试组 9测试组 10
普通函数计算结果-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222
内联函数计算结果-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222
__fastcall函数计算结果-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222
虚函数函数计算结果-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222
__vectorcall函数计算结果-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222-2.72222
普通函数所用时间254098198315295810196010231354227261234529193469208299194281
内联函数所用时间204532207672220823193657251189214864235892189333197464191431
__fastcall函数所用时间219724202143196455193939206037191861234598227355208511222972
虚函数函数所用时间249393226958214917215913216678215154275628223812217290214860
__vectorcall函数所用时间240161201210192023277484223628195951200724195849194678195168
普通函数所用时间最大/小值最大值295810最小值193469
内联函数所用时间最大/小值最大值251189最小值189333
__fastcall函数所用时间最大/小值最大值234598最小值191861
虚函数函数所用时间最大/小值最大值275628最小值214860
__vectorcall函数所用时间最大/小值最大值277484最小值192023
普通函数所用时间平均值218018
内联函数所用时间平均值208292
__fastcall函数所用时间平均值209642
虚函数函数所用时间平均值222514
__vectorcall函数所用时间平均值205921

第二次测试结果:
++ 普通函数调用调用平均时间:202104
++ 内联函数调用调用平均时间:199590
++ __fastcall函数调用调用平均时间:200249
++ 虚函数调用调用平均时间:218817
++ __vectorcall函数调用调用平均时间:204897

第三次测试结果
++ 普通函数调用调用平均时间:191915
++ 内联函数调用调用平均时间:190074
++ __fastcall函数调用调用平均时间:194492
++ 虚函数调用调用平均时间:222944
++ __vectorcall函数调用调用平均时间:196064

因为优化关系,大致时间消耗 :
内联 < 普通函数(寄存器优化)、__fastcall 、__vectorcall < 虚函数
因为虚函数涉及堆变量存取以及每次调用的查表操作,时间要慢一些,在本例函数调用测试中,成本在原函数 1.1 ± 0.05左右

附页

代码清单:

class A {
public:
	virtual double virtual_func(double x, double y, double z) { return 0.0; }
	double mem = 0.0;
};

class B :public A {
public:
	virtual double virtual_func(double x, double y, double z);
};

double B::virtual_func(double x, double y, double z) {
	double ret = -x * mem - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * mem - x * y + z * mem;
	ret ;
	return mem += (ret/ 100.0);
}


#include "pch.h"
#include <iostream>
#include <vector>
#include <Windows.h>

using namespace std;


__forceinline double inline_func(double x, double y, double z, double w) {
	double ret = -x * w - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * w - x * y + z * w;
	return ret / 100.0;
}

double normal_func(double x, double y, double z, double w) {
	double ret = -x * w - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * w - x * y + z * w;
	return ret / 99.0;
}

double __fastcall fast_func(double x, double y, double z, double w) {
	double ret = -x * w - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * w - x * y + z * w;
	return ret / 100.0;
}

double __vectorcall vector_func(double x, double y, double z, double w) {
	double ret = -x * w - y * z - x * z;
	ret *= x;
	ret -= y * z;
	ret = -ret;
	ret /= y * w - x * y + z * w;
	return ret / 100.0;
}

A *obj = new B;

int main(){
	
	// 初始化区域
	LARGE_INTEGER freq; 
	QueryPerformanceFrequency(&freq);	// 获取计时器精度
	const double a = 1000000.0 / freq.QuadPart;	// 计时精度纳秒

	LARGE_INTEGER begin_time;
	LARGE_INTEGER end_time;

	double value = 0.0;		// 迭代值
	double ns_time = 0.0;	// 所用时间

	constexpr int data_count = 5;	// 测试函数种类数量
	constexpr int group_count = 10;	// 测试次数
	constexpr int call_count = 10000000; // 调用次数

	double time_arr[data_count][group_count] = { 0.0 };	// 记录函数每次测试调用时间
	double result_arr[data_count][group_count] = { 0.0 }; // 统计迭代计算结果
	

	for (int j = 0, j_end = group_count; j < j_end; ++j) {
		// ********************************************************
		// ********************************************************
		// 普通函数调用
		QueryPerformanceCounter(&begin_time);

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += normal_func(0.3, 0.2, 0.7, value);
		}

		QueryPerformanceCounter(&end_time);
		ns_time = (end_time.QuadPart - begin_time.QuadPart) * a;

		time_arr[0][j] = ns_time;
		result_arr[0][j] = value;

		// ********************************************************
		// ********************************************************
		// 内联函数调用
		value = 0.0;
		ns_time = 0.0;
		QueryPerformanceCounter(&begin_time);

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += inline_func(0.3, 0.2, 0.7, value);
		}

		QueryPerformanceCounter(&end_time);
		ns_time = (end_time.QuadPart - begin_time.QuadPart) * a;
	
		time_arr[1][j] = ns_time;
		result_arr[1][j] = value;
		// ********************************************************
		// ********************************************************
		// __fastcall
		value = 0.0;
		ns_time = 0.0;
		QueryPerformanceCounter(&begin_time);

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += fast_func(0.3, 0.2, 0.7, value);
		}

		QueryPerformanceCounter(&end_time);
		ns_time = (end_time.QuadPart - begin_time.QuadPart) * a;

		time_arr[2][j] = ns_time;
		result_arr[2][j] = value;
		// ********************************************************
		// ********************************************************
		// 虚函数
		value = 0.0;
		ns_time = 0.0;
		obj->mem = 0.0;
		QueryPerformanceCounter(&begin_time);

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += obj->virtual_func(0.3, 0.2, 0.7);
			// 虽然这里虚函数内部计算了,但还是写出来
		}

		QueryPerformanceCounter(&end_time);
		ns_time = (end_time.QuadPart - begin_time.QuadPart) * a;

		time_arr[3][j] = ns_time;
		result_arr[3][j] = obj->mem;
		// ********************************************************
		// ********************************************************
		// __vectorcall
		value = 0.0;
		ns_time = 0.0;
		QueryPerformanceCounter(&begin_time);

		for (int i = 0, i_end = call_count; i < i_end; ++i) {
			value += vector_func(0.3, 0.2, 0.7, value);
		}

		QueryPerformanceCounter(&end_time);
		ns_time = (end_time.QuadPart - begin_time.QuadPart) * a;

		time_arr[4][j] = ns_time;
		result_arr[4][j] = value;
	}

	// 函数种类标识
	const char* name_arr[data_count] = {
		"普通函数调用",
		"内联函数调用",
		"__fastcall函数调用",
		"虚函数调用",
		"__vectorcall函数调用",};

	// 打印迭代结算结果
	std::cout << "计算完毕,打印结果:" << endl;
	for (int j = 0, j_end = data_count; j < j_end; ++j) {
		std::cout << name_arr[j] << "计算结果:" << endl;
		for (int i = 0, i_end = group_count; i < i_end; ++i) {
			std::cout << result_arr[j][i] << ",";
		}
		std::cout << std::endl;
	}
	
	// 打印每组测试所用时间,并统计最大最小值下标
	std::cout << endl << endl;
	int max_index[data_count] = { 0 };
	int min_index[data_count] = { 0 };
	double sum[data_count] = { 0.0 };
	for (int j = 0, j_end = data_count; j < j_end; ++j) {
		std::cout << name_arr[j] << "所用时间:" << endl;
		for (int i = 0, i_end = group_count; i < i_end; ++i) {
			std::cout << time_arr[j][i] << ",";
			if (time_arr[j][i] > time_arr[j][max_index[j]]) { max_index[j] = i; }
			if (time_arr[j][i] < time_arr[j][min_index[j]]) { min_index[j] = i; }
			sum[j] += time_arr[j][i];
		}
		std::cout << endl;
	}
	std::cout << endl << endl;
	for (int j = 0, j_end = data_count; j < j_end; ++j) {
		std::cout << name_arr[j] << "时间最大值:" ;
		std::cout << time_arr[j][max_index[j]] << endl;
		std::cout << name_arr[j] << "时间最小值:";
		std::cout << time_arr[j][min_index[j]] << endl;
		sum[j] -= time_arr[j][max_index[j]];
		sum[j] -= time_arr[j][min_index[j]];
	}
	std::cout << endl << endl;

	// 打印统计结果
	std::cout << "统计完毕,除去一个最大值一个最小值,打印结果:" << endl;
	for (int j = 0, j_end = data_count; j < j_end; ++j) {
		std::cout << "  ++ " << name_arr[j] << "调用平均时间:" << sum[j] / 8.0 << endl;
	}


	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值