Measuring virtual function call cost
C++ version See stopwatch
C++, _SECURE_SCL 0, vector of function pointers, __fastcall
//#define FCALLTYPE //#define FCALLTYPESTR "__cdecl" #define FCALLTYPE __fastcall #define FCALLTYPESTR "__fastcall" typedef void (FCALLTYPE *SumPF)(int &); void FCALLTYPE OddSum(int &s) { s += 1; } void FCALLTYPE EvenSum(int &s) { s += 2; } int main() { using namespace std; vector<SumPF> v; v.push_back(&OddSum); v.push_back(&EvenSum); Stopwatch sw; sw.Start(); int sum = 0; const int maxit = 100000000; for (int i = 0; i < maxit; ++i) { vector<SumPF>::iterator it = v.begin(); for (; it != v.end(); ++it) { (*it)(sum); } } sw.Stop(); cout << "/**C++, _SECURE_SCL 0, vector of function pointers, " << FCALLTYPESTR << "*/" << endl; cout << "iterations =" << maxit << endl; cout << "sum =" << sum << endl; cout << "Elapsed =" << sw << endl; cout << "Average =" << sw.GetElapsedMilliseconds() / double(maxit) << " milliseconds/call"; cin.get(); }
C++, _SECURE_SCL 0, direct base class call
#define FCALLTYPE #define FCALLTYPESTR "__cdecl" //#define FCALLTYPE __fastcall //#define FCALLTYPESTR "__fastcall" struct Base { virtual void FCALLTYPE Sum(int &s) = 0; virtual ~Base(){} }; struct Odd : public Base { void FCALLTYPE Sum(int &s) { s += 1; } }; struct Even : public Base { void FCALLTYPE Sum(int &s) { s += 2; } }; int main() { using namespace std; Base* podd(new Odd()); Base* peven(new Even()); Stopwatch sw; sw.Start(); int sum = 0; const int maxit = 100000000; for (int i = 0; i < maxit; ++i) { podd->Sum(sum); peven->Sum(sum); } sw.Stop(); cout << "/**C++, _SECURE_SCL 0, direct base class call, " << FCALLTYPESTR << "*/" << endl; cout << "iterations =" << maxit << endl; cout << "sum =" << sum << endl; cout << "Elapsed =" << sw << endl; cout << "Average =" << sw.GetElapsedMilliseconds() / double(maxit) << " milliseconds/call"; cin.get(); delete podd; delete peven; }
C++, _SECURE_SCL 0, vector base class call
//#define FCALLTYPE //#define FCALLTYPESTR "__cdecl" #define FCALLTYPE __fastcall #define FCALLTYPESTR "__fastcall" struct Base { virtual void FCALLTYPE Sum(int &s) = 0; virtual ~Base(){} }; struct Odd : public Base { void FCALLTYPE Sum(int &s) { s += 1; } }; struct Even : public Base { void FCALLTYPE Sum(int &s) { s += 2; } }; int main() { using namespace std; vector<Base*> v; v.push_back(new Odd()); v.push_back(new Even()); Stopwatch sw; sw.Start(); int sum = 0; const int maxit = 100000000; for (int i = 0; i < maxit; ++i) { vector<Base*>::iterator it = v.begin(); for (; it != v.end(); ++it) { (*it)->Sum(sum); } } sw.Stop(); cout << "/**C++, _SECURE_SCL 0, vector base class call, " << FCALLTYPESTR << "*/" << endl; cout << "iterations =" << maxit << endl; cout << "sum =" << sum << endl; cout << "Elapsed =" << sw << endl; cout << "Average =" << sw.GetElapsedMilliseconds() / double(maxit) << " milliseconds/call"; for (vector<Base*>::iterator it = v.begin(); it != v.end(); ++it) { delete *it; } cin.get(); }
C# base call
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace ConsoleApplication1 { abstract class Base { public abstract void Sum(ref int s); }; class Odd : Base { public override void Sum(ref int s) { s += 1; } }; class Even : Base { public override void Sum(ref int s) { s += 2; } }; class Program { static void Main(string[] args) { List<Base> list = new List<Base>(); list.Add(new Odd()); list.Add(new Even()); Stopwatch sw = new Stopwatch(); sw.Start(); int sum = 0; const int maxit = 100000000; for (int i = 0; i < maxit; ++i) { for (int k = 0; k < list.Count; k++) { list[k].Sum(ref sum); } } sw.Stop(); Console.WriteLine("iterations : {0}", maxit); Console.WriteLine("sum : {0}", sum); Console.WriteLine("Elapsed : {0}", sw.ElapsedMilliseconds); Console.WriteLine("Average : {0}", sw.ElapsedMilliseconds / (double)maxit); Console.Read(); } } }
C# list
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace ConsoleApplication1 { abstract class Base { public abstract void Sum(ref int s); }; class Odd : Base { public override void Sum(ref int s) { s += 1; } }; class Even : Base { public override void Sum(ref int s) { s += 2; } }; class Program { static void Main(string[] args) { Base odd = new Odd(); Base even = new Even(); Stopwatch sw = new Stopwatch(); sw.Start(); int sum = 0; const int maxit = 100000000; for (int i = 0; i < maxit; ++i) { odd.Sum(ref sum); even.Sum(ref sum); } sw.Stop(); Console.WriteLine("iterations : {0}", maxit); Console.WriteLine("sum : {0}", sum); Console.WriteLine("Elapsed : {0}", sw.ElapsedMilliseconds); Console.WriteLine("Average : {0}", sw.ElapsedMilliseconds / (double)maxit); Console.Read(); } } }
C++, _SECURE_SCL 0, direct base class call, __cdecl
iterations =100000000 sum =300000000 Elapsed =1695 ms (stopped) Average =1.695e-005 milliseconds/call
C++, _SECURE_SCL 0, direct base class call, __fastcall
iterations =100000000 sum =300000000 Elapsed =769 ms (stopped) Average =7.69e-006 milliseconds/call
C++, _SECURE_SCL 0, vector of function pointers, __cdecl
iterations =100000000 sum =300000000 Elapsed =2653 ms (stopped) Average =2.653e-005 milliseconds/call
C++, _SECURE_SCL 0, vector of function pointers, __fastcall
iterations =100000000 sum =300000000 Elapsed =2549 ms (stopped) Average =2.549e-005 milliseconds/call
C++, _SECURE_SCL 0, vector base class call, __cdecl
iterations =100000000 sum =300000000 Elapsed =3424 ms (stopped) Average =3.424e-005 milliseconds/call
C++, _SECURE_SCL 0, vector base class call, __fastcall
iterations =100000000 sum =300000000 Elapsed =3320 ms (stopped) Average =3.32e-005 milliseconds/call
C++, _SECURE_SCL 0, vector base class call, __fastcall, __fastcall in project config
iterations =100000000 sum =300000000 Elapsed =3078 ms (stopped) Average =3.078e-005 milliseconds/call
C# base call
iterations : 100000000 sum : 300000000 Elapsed : 984 Average : 9,84E-06
C# list
iterations : 100000000 sum : 300000000 Elapsed : 3293 Average : 3,293E-05
Brief
C++ vector function ptr 2549 C++ vector 3078 C# list 3293 ~ +6% C++ base call 769 c# base call 984 ~ +27%
Thanks Felipe Farion to point out the use of __fastcall VC++ 2008, uses __cdecl by default.