Advertisement
Guest User

Untitled

a guest
May 11th, 2017
339
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.54 KB | None | 0 0
  1. #include <Windows.h>
  2. #include <intrin.h>
  3. #include <cstddef>
  4. #include <iostream>
  5. #include <cstdint>
  6. #include <cassert>
  7. #include <cstdio>
  8. #include <string>
  9. #include <sstream>
  10. #include "../common/xstddef.h"
  11.  
  12. using namespace std;
  13. using namespace ns_OClasses;
  14.  
  15. struct TlbInfo
  16. {
  17.     static unsigned const LEVEL1    = 0,
  18.                           LEVEL2    = 1,
  19.                           PAGES_4KB = 0,
  20.                           PAGES_4MB = 1;
  21.     struct
  22.     {
  23.         struct
  24.         {
  25.             bool     fKnown;
  26.             unsigned entries;
  27.             int      associativity;
  28.         } aPageSizes[2];
  29.     } aLevels[2];
  30. };
  31.  
  32. union CacheLineChain
  33. {
  34.     CacheLineChain volatile *pclcNext;
  35. };
  36.  
  37. void AutoExit( bool fExit, char *message );
  38. bool GetCacheInfo( unsigned level, size_t *pSize, unsigned *pAssociativity, unsigned *pLineSizeShift, unsigned *pSectors );
  39. void GetTlbInfo( TlbInfo *pTlbInfo );
  40.  
  41. size_t InitializePointerChain( void *pBlock, unsigned blockBits, unsigned randBlockBits , unsigned lineBits );
  42. string GetSizeString( unsigned blockBits );
  43.  
  44. int main()
  45. {
  46.     unsigned const  MAX_BLOCK_BITS = 28; // 256MB
  47.     TlbInfo         ti;
  48.     SYSTEM_INFO     si;
  49.     unsigned        pageBits;
  50.     unsigned        lineBits;
  51.     unsigned        rbBits;
  52.     void           *pBlock;
  53.    
  54.     AutoExit( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ), "can't set process-priority" );;
  55.     AutoExit( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST ), "can't set thread-priority" );;
  56.     AutoExit( SetThreadAffinityMask( GetCurrentThread(), 1 ) == 0, "can't set thread affinity");
  57.  
  58.     GetTlbInfo( &ti );
  59.     AutoExit( !ti.aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].fKnown, "can't determine l1 dtlb-size" );
  60.     GetSystemInfo( &si );
  61.     pageBits = floor_log2<DWORD>( si.dwPageSize );
  62.     AutoExit( !GetCacheInfo( 1, nullptr, nullptr, &lineBits, nullptr ), "can't determine l1-cache parameters" );
  63.     rbBits = floor_log2<unsigned>( ti.aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].entries ) + pageBits;
  64.  
  65.     AutoExit( (pBlock = VirtualAlloc( NULL, (size_t)1 << MAX_BLOCK_BITS, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE )) == NULL, "can't allocate memory for test-block" );
  66.  
  67.     unsigned                 blockBits;
  68.     size_t                   nCacheLines;
  69.     DWORDLONG                dwlTick,
  70.                              dwlFastestTick;
  71.     unsigned                 turn;
  72.     double                   ticksPerCacheline;
  73.  
  74.     for( blockBits = pageBits; blockBits <= MAX_BLOCK_BITS; blockBits++ )
  75.     {
  76.         nCacheLines = InitializePointerChain( pBlock, blockBits, rbBits, lineBits );
  77.  
  78.         for( dwlFastestTick = (DWORDLONG)(LONGLONG)-1, turn = 0; turn < 100; turn++ )
  79.         {
  80.             dwlTick        = __rdtsc();
  81.             for( CacheLineChain volatile *pclc = (CacheLineChain *)pBlock; (pclc = pclc->pclcNext) != nullptr; );
  82.             dwlTick        = __rdtsc() - dwlTick;
  83.             dwlFastestTick = dwlTick < dwlFastestTick ? dwlTick : dwlFastestTick;
  84.         }
  85.  
  86.         ticksPerCacheline = (double)dwlFastestTick / nCacheLines;
  87.         cout << GetSizeString( blockBits ) << " " << ticksPerCacheline << endl;
  88.     }
  89.  
  90.     return EXIT_SUCCESS;
  91. }
  92.  
  93. uint64_t ReverseBits( uint64_t reverse, unsigned bits );
  94.  
  95. size_t InitializePointerChain( void *pBlock, unsigned blockBits, unsigned randBlockBits , unsigned lineBits )
  96. {
  97.     assert(blockBits > lineBits);
  98.  
  99.     union ClcPointer
  100.     {
  101.         BYTE                    *pbCl;
  102.         CacheLineChain volatile *pclc;
  103.     };
  104.  
  105.     CacheLineChain volatile *pclcFirst,
  106.                             *pclcPrev;
  107.     ClcPointer               cpRandBlock,
  108.                              cp;
  109.     size_t                   randBlock,
  110.                              reverseCacheLine,
  111.                              nRandBlocks;
  112.  
  113.     pclcFirst        = (CacheLineChain *)pBlock;
  114.     cpRandBlock.pclc = pclcFirst;
  115.     pclcPrev         = nullptr;
  116.     nRandBlocks      = (size_t)1 << (blockBits >= randBlockBits ? blockBits - randBlockBits : 0);
  117.     randBlock        = 0;
  118.     do
  119.     {
  120.         reverseCacheLine = 0;
  121.         do
  122.         {
  123.             cp.pbCl = &cpRandBlock.pbCl[(size_t)ReverseBits( reverseCacheLine, blockBits >= randBlockBits ? randBlockBits - lineBits : blockBits - lineBits ) << lineBits];
  124.             if( pclcPrev )
  125.                 pclcPrev->pclcNext = cp.pclc;
  126.             pclcPrev = cp.pclc;
  127.         } while( ++reverseCacheLine < ((size_t)1 << (blockBits >= randBlockBits ? randBlockBits - lineBits : blockBits - lineBits)) );
  128.         cpRandBlock.pbCl += (size_t)1 << randBlockBits;
  129.     } while( ++randBlock < nRandBlocks );
  130.     pclcPrev->pclcNext = nullptr;
  131.  
  132.     return (size_t)1 << (blockBits - lineBits);
  133. }
  134.  
  135. string GetSizeString( unsigned blockBits )
  136. {
  137.     size_t size;
  138.     stringstream ss;
  139.  
  140.     if( (size = (size_t)1 << blockBits) < 1024 )
  141.         ss << size << "B";
  142.     else if( size < (1024 * 1024) )
  143.         ss << (size / 1024) << "kB";
  144.     else if( size < (1024 * 1024 * 1024) )
  145.         ss << (size / (1024 * 1024)) << "MB";
  146.     else
  147.         ss << (size / (1024 * 1024 * 1024)) << "GB";
  148.  
  149.     return ss.str();
  150. }
  151.  
  152. void AutoExit( bool fExit, char *message )
  153. {
  154.     if( fExit )
  155.     {
  156.         cout << message << endl;
  157.         getchar();
  158.         ExitProcess( EXIT_FAILURE );
  159.     }
  160. }
  161.  
  162.  
  163. uint64_t ReverseBits( uint64_t reverse, unsigned bits )
  164. {
  165.     assert(bits >= 1 && bits <= 64);
  166.     reverse   = ((reverse & 0xFFFFFFFF00000000) >> 32) | ((reverse & 0x00000000FFFFFFFF) << 32);
  167.     reverse   = ((reverse & 0xFFFF0000FFFF0000) >> 16) | ((reverse & 0x0000FFFF0000FFFF) << 16);
  168.     reverse   = ((reverse & 0xFF00FF00FF00FF00) >>  8) | ((reverse & 0x00FF00FF00FF00FF) <<  8);
  169.     reverse   = ((reverse & 0xF0F0F0F0F0F0F0F0) >>  4) | ((reverse & 0x0F0F0F0F0F0F0F0F) <<  4);
  170.     reverse   = ((reverse & 0xCCCCCCCCCCCCCCCC) >>  2) | ((reverse & 0x3333333333333333) <<  2);
  171.     reverse   = ((reverse & 0xAAAAAAAAAAAAAAAA) >>  1) | ((reverse & 0x5555555555555555) <<  1);
  172.     reverse >>= 64 - bits;
  173.  
  174.     return reverse;
  175. }
  176.  
  177. DWORD CpuId( DWORD dwCode, DWORD dwEcx2ndParameter, DWORD *pdwRegisters );
  178.  
  179. bool GetCacheInfo( unsigned level, size_t *pSize, unsigned *pAssociativity, unsigned *pLineSizeShift, unsigned *pSectors )
  180. {
  181.     DWORD adwCpuIdRetRegisters[4];
  182.  
  183.     if( (CpuId( 0, 0, adwCpuIdRetRegisters ),
  184.          adwCpuIdRetRegisters[1] == 'uneG' &&
  185.          adwCpuIdRetRegisters[3] == 'Ieni' &&
  186.          adwCpuIdRetRegisters[2] == 'letn') )
  187.         return false;
  188.  
  189.     if( adwCpuIdRetRegisters[1] == 'htuA' &&
  190.         adwCpuIdRetRegisters[3] == 'itne' &&
  191.         adwCpuIdRetRegisters[2] == 'DMAc' &&
  192.         CpuId( 0x80000000u, 0, adwCpuIdRetRegisters ) >= (0x80000005u + (level > 1)) )
  193.     {
  194.         size_t   size;
  195.         unsigned associativity;
  196.         unsigned clShift;
  197.         unsigned sectors;
  198.  
  199.         CpuId( 0x80000005u + (level > 1), 0, adwCpuIdRetRegisters );
  200.  
  201.         if( level == 1 )
  202.             size          = (adwCpuIdRetRegisters[2] >> 24) * 1024,
  203.             associativity = (unsigned)(signed char)(adwCpuIdRetRegisters[2] >> 16),
  204.             clShift       = floor_log2<DWORD>( adwCpuIdRetRegisters[2] & 0x0FF ),
  205.             sectors       = (unsigned)((adwCpuIdRetRegisters[2] >> 8) & 0x0FF);
  206.         else if( level == 2 )
  207.             size          = (adwCpuIdRetRegisters[2] >> 16) * 1024,
  208.             associativity = (unsigned)(signed char)((adwCpuIdRetRegisters[2] >> 12) & 0x0F),
  209.             clShift       = floor_log2<DWORD>( adwCpuIdRetRegisters[2] & 0x0FF ),
  210.             sectors       = (unsigned)((adwCpuIdRetRegisters[2] >> 8) & 0x0F);
  211.         else if( level == 3 )
  212.             size          = ((adwCpuIdRetRegisters[3] >> 18) & 0x3FFF) * 512 * 1024,
  213.             associativity = (unsigned)(signed char)((adwCpuIdRetRegisters[3] >> 12) & 0x0F),
  214.             clShift       = floor_log2<DWORD>( adwCpuIdRetRegisters[3] & 0x0FF ),
  215.             sectors       = (unsigned)((adwCpuIdRetRegisters[2] >> 8) & 0x0F);
  216.         else
  217.             return false;
  218.  
  219.         if( pSize )
  220.             *pSize = size;
  221.  
  222.         if( pAssociativity )
  223.             *pAssociativity = associativity;
  224.  
  225.         if( pLineSizeShift )
  226.             *pLineSizeShift = clShift;
  227.  
  228.         if( pSectors )
  229.             *pSectors = sectors;
  230.  
  231.         return true;
  232.     }
  233.  
  234.     return false;
  235. }
  236.  
  237. void GetTlbInfo( TlbInfo *pti )
  238. {
  239.     DWORD adwCpuidRetRegisters[4];
  240.     DWORD dwMaxExtendedCpuId;
  241.  
  242.     pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4KB].fKnown = false;
  243.     pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].fKnown = false;
  244.     pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4KB].fKnown = false;
  245.     pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4MB].fKnown = false;
  246.  
  247.     if( (CpuId( 0, 0, adwCpuidRetRegisters ),
  248.          adwCpuidRetRegisters[1] == 'uneG' &&
  249.          adwCpuidRetRegisters[3] == 'Ieni' &&
  250.          adwCpuidRetRegisters[2] == 'letn') )
  251.         return;
  252.  
  253.     if( (CpuId( 0, 0, adwCpuidRetRegisters ),
  254.          adwCpuidRetRegisters[1] == 'htuA' &&
  255.          adwCpuidRetRegisters[3] == 'itne' &&
  256.          adwCpuidRetRegisters[2] == 'DMAc') &&
  257.         (dwMaxExtendedCpuId = CpuId( 0x80000000u, 0, adwCpuidRetRegisters )) >= 0x80000005u )
  258.     {
  259.         int associativity;
  260.  
  261.         CpuId( 0x80000005u, 0, adwCpuidRetRegisters );
  262.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4KB].fKnown        = true;
  263.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4KB].entries       =         (unsigned)((adwCpuidRetRegisters[1] & 0x00FF0000u) >> 16);
  264.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4KB].associativity = (int)(signed char)((adwCpuidRetRegisters[1] & 0xFF000000u) >> 24);
  265.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].fKnown        = true;
  266.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].entries       =         (unsigned)((adwCpuidRetRegisters[0] & 0x00FF0000u) >> 16);
  267.         pti->aLevels[TlbInfo::LEVEL1].aPageSizes[TlbInfo::PAGES_4MB].associativity = (int)(signed char)((adwCpuidRetRegisters[0] & 0xFF000000u) >> 24);
  268.  
  269.         if( dwMaxExtendedCpuId >= 0x80000006u )
  270.             CpuId( 0x80000006u, 0, adwCpuidRetRegisters ),
  271.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4KB].fKnown        = true,
  272.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4KB].entries       = (unsigned)((adwCpuidRetRegisters[1] & 0x0FFF0000u) >> 16),
  273.             associativity                                                              = (int)((adwCpuidRetRegisters[1] & 0xF0000000u) >> 28),
  274.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4KB].associativity = (associativity < 0xF) ? associativity : -1,
  275.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4MB].fKnown        = true,
  276.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4MB].entries       = (unsigned)((adwCpuidRetRegisters[0] & 0x0FFF0000u) >> 16),
  277.             associativity                                                              = (int)((adwCpuidRetRegisters[0] & 0xF0000000u) >> 28),
  278.             pti->aLevels[TlbInfo::LEVEL2].aPageSizes[TlbInfo::PAGES_4MB].associativity = (associativity < 0xF) ? associativity : -1;
  279.  
  280.     }
  281. }
  282.  
  283. DWORD CpuId( DWORD dwCode, DWORD dwEcx2ndParameter, DWORD *pdwRegisters )
  284. {
  285.     int aRegs[4];
  286.  
  287.     __cpuidex( aRegs, (int)dwCode, (int)dwEcx2ndParameter );
  288.     for( int i = 0; i < 4; pdwRegisters[i] = (DWORD)aRegs[i], i++ );
  289.  
  290.     return (DWORD)aRegs[0];
  291. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement