Advertisement
Guest User

C++ vs C vs clever C++

a guest
Aug 16th, 2012
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.34 KB | None | 0 0
  1. ====================================================
  2. Results (seconds, lower is better)
  3. ====================================================
  4.    Total   Derived   Base
  5. 1) 0.38    0.09      0.29
  6. 2) 0.38    0.09      0.29
  7. 3) 0.41    0.09      0.32
  8.  
  9. ====================================================
  10. Disassembly
  11. ====================================================
  12.  
  13. Version1
  14.             base->DoStuff();
  15. 002B3EF4  mov         eax,dword ptr [esp+60h]
  16. 002B3EF8  mov         edx,dword ptr [eax]
  17. 002B3EFA  lea         ecx,[esp+60h]
  18. 002B3EFE  mov         dword ptr [esp+64h],edi
  19. 002B3F02  call        edx  
  20.     struct B : public A { void DoStuff() { b = a; } int b; };
  21. 002B32A0  mov         eax,dword ptr [ecx+4]
  22. 002B32A3  mov         dword ptr [ecx+8],eax
  23. 002B32A6  ret              
  24.  
  25. Version2
  26.             A_DoStuff( base );
  27. 002B3FB0  mov         ecx,dword ptr [esp+60h]
  28. 002B3FB4  lea         eax,[esp+60h]
  29. 002B3FB8  mov         dword ptr [esp+64h],edi
  30. 002B3FBC  mov         edx,dword ptr [ecx]
  31. 002B3FBE  push        eax  
  32. 002B3FBF  call        edx  
  33.     void B_DoStuff( B* obj ) { obj->b = obj->base.a; }
  34. 002B32C0  mov         eax,dword ptr [esp+4]
  35. 002B32C4  mov         ecx,dword ptr [eax+4]
  36. 002B32C7  mov         dword ptr [eax+8],ecx
  37. 002B32CA  ret              
  38.  
  39. Version3
  40.             base->DoStuff();
  41. 002B4070  lea         ecx,[esp+74h]
  42. 002B4074  mov         dword ptr [esp+78h],edi
  43. 002B4078  call        dword ptr [esp+74h]
  44.         void DoStuff() { b = a; }
  45. 002B3300  mov         eax,dword ptr [ecx+4]
  46. 002B3303  mov         dword ptr [ecx+8],eax
  47. 002B3306  ret              
  48.  
  49.  
  50. ====================================================
  51. C++ code
  52. ====================================================
  53. #define FORCEINLINE __forceinline
  54. #define FASTCALL __fastcall
  55. namespace Version1
  56. {
  57.     struct A { virtual void DoStuff() {}; int a; };
  58.     struct B : public A { void DoStuff() { b = a; } int b; };
  59. }
  60. namespace Version2 // translate Version1 into C
  61. {
  62.     struct A;
  63.     struct A_VTable { typedef void (*FnDoStuff)(A*); FnDoStuff DoStuff; };
  64.     struct A { A_VTable* vtable; int a; };
  65.     FORCEINLINE void FASTCALL A_DoStuff( A* obj ) { (*obj->vtable->DoStuff)(obj); }
  66.     struct B { A base; int b; };
  67.     void B_DoStuff( B* obj ) { obj->b = obj->base.a; }
  68.     A_VTable g_B_VTable = { (A_VTable::FnDoStuff)&B_DoStuff };
  69.     FORCEINLINE void FASTCALL B_Construct( B* obj ) { obj->base.vtable = &g_B_VTable; }
  70.     B obj;
  71. }
  72. namespace Version3 // optimize version2 by embedding the vtable in the object
  73. {
  74.     struct A {
  75.         typedef void (A::*FnDoStuff)();
  76.         FORCEINLINE A(FnDoStuff p) : pfnDoStuff(p) {}
  77.         FnDoStuff pfnDoStuff;
  78.         int a;
  79.         FORCEINLINE void FASTCALL DoStuff() { (this->*pfnDoStuff)(); }
  80.     };
  81.     struct B : public A {
  82.         FORCEINLINE B() : A(static_cast<FnDoStuff>(&B::DoStuff)) {}
  83.         void DoStuff() { b = a; }
  84.         int b;
  85.     };
  86. }
  87.  
  88. static const int cacheSize = eiMiB(10);
  89. int FlushCache(void* cache)
  90. {
  91.     memset(cache, 0, cacheSize);
  92.     int result = 0;
  93.     int* data = (int*)cache;
  94.     for( int i=0; i<(cacheSize/sizeof(int)); ++i )
  95.         result += data[i];
  96.     return result;
  97. }
  98.  
  99. #include <stdio.h>
  100. void TestAB(Timer& timer)
  101. {
  102.     void* cache = malloc(cacheSize);
  103.     double v1Derived = 0, v2Derived = 0, v3Derived = 0;
  104.     double v1Base = 0, v2Base = 0, v3Base = 0;
  105.     double v1Total = 0, v2Total = 0, v3Total = 0;
  106.     int dontOptimize1 = 0, dontOptimize2 = 0, dontOptimize3 = 0;
  107.     int stress = 10000;
  108.  
  109.     dontOptimize1 += FlushCache(cache);
  110.     double v1Start = timer.Elapsed();
  111.     for( int c=0; c!=stress; ++c )
  112.     {
  113.         Version1::B obj;
  114.         Version1::A* base = &obj;
  115.         double start = timer.Elapsed();
  116.         for( int i=0; i!=stress; ++i )
  117.         {
  118.             obj.a = i;
  119.             obj.DoStuff();
  120.         }
  121.         v1Derived += timer.Elapsed() - start;
  122.         start = timer.Elapsed();
  123.         for( int i=0; i!=stress; ++i )
  124.         {
  125.             base->a = i;
  126.             base->DoStuff();
  127.         }
  128.         v1Base += timer.Elapsed() - start;
  129.         dontOptimize1 += obj.b;
  130.     }
  131.     v1Total = timer.Elapsed() - v1Start;
  132.  
  133.     dontOptimize2 += FlushCache(cache);
  134.     double v2Start = timer.Elapsed();
  135.     for( int c=0; c!=stress; ++c )
  136.     {
  137.         Version2::B obj;
  138.         B_Construct( &obj );
  139.         Version2::A* base = &obj.base;
  140.         double start = timer.Elapsed();
  141.         for( int i=0; i!=stress; ++i )
  142.         {
  143.             obj.base.a = i;
  144.             B_DoStuff( &obj );
  145.         }
  146.         v2Derived += timer.Elapsed() - start;
  147.         start = timer.Elapsed();
  148.         for( int i=0; i!=stress; ++i )
  149.         {
  150.             base->a = i;
  151.             A_DoStuff( base );
  152.         }
  153.         v2Base += timer.Elapsed() - start;
  154.         dontOptimize2 += obj.b;
  155.     }
  156.     v2Total = timer.Elapsed() - v2Start;
  157.  
  158.     dontOptimize3 += FlushCache(cache);
  159.     double v3Start = timer.Elapsed();
  160.     for( int c=0; c!=stress; ++c )
  161.     {
  162.         Version3::B obj;
  163.         Version3::A* base = &obj;
  164.         double start = timer.Elapsed();
  165.         for( int i=0; i!=stress; ++i )
  166.         {
  167.             obj.a = i;
  168.             obj.DoStuff();
  169.         }
  170.         v3Derived += timer.Elapsed() - start;
  171.         start = timer.Elapsed();
  172.         for( int i=0; i!=stress; ++i )
  173.         {
  174.             base->a = i;
  175.             base->DoStuff();
  176.         }
  177.         v3Base += timer.Elapsed() - start;
  178.         dontOptimize3 += obj.b;
  179.     }
  180.     v3Total = timer.Elapsed() - v3Start;
  181.  
  182.     eiASSERT( dontOptimize1 == dontOptimize2 );
  183.     eiASSERT( dontOptimize1 == dontOptimize3 );
  184.  
  185.     free(cache);
  186.  
  187.     printf( "   Total   Derived   Base\n", dontOptimize1, dontOptimize2, dontOptimize3 );
  188.     printf( "1) %.2f    %.2f      %.2f\n", v1Total, v1Derived, v1Base );
  189.     printf( "2) %.2f    %.2f      %.2f\n", v2Total, v2Derived, v2Base );
  190.     printf( "3) %.2f    %.2f      %.2f\n", v3Total, v3Derived, v3Base );
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement