SORU
14 Temmuz 2009, Salı


L1 Önbelleği Maliyetini Bayan nedir?

Edit: Referans amaçlı eğer herkes bu soruya tökezledi değilseniz, Igor Ostrovsky great post yaklaşık bir önbellek özlüyor yazdı. Çeşitli konularda tartışır ve örnek sayıları verilmiştir.Düzenleme Sonunda

Bazı test <long story goes here> yaptım ve eğer bir performans farkı önbellek özlüyor kaynaklanıyor merak ediyorum. Aşağıdaki kodu sorun gösterir ve kritik zamanlama kısmı için aşağı kaynar. Aşağıdaki kodu rastgele hafıza ziyaret ve artan sipariş adresi daha sonra bu döngüler bir çift var.

Bir Linux (gcc –Os) üzerinde XP makine (VS2005 ile derlenmiş: /O2 cl) ve koştum. Her ikisi de benzer zamanlarda üretti. Bu kez, milisaniye cinsinden. Tüm döngüleri çalışan ve optimize değil inanıyorum (aksi takdirde aday olacağını“”) anında.

*** Testing 20000 nodes
Total Ordered Time: 888.822899
Total Random Time: 2155.846268

Bu sayıların bir anlamı? Fark L1 önbellek özlüyor nedeniyledir ya da başka bir şey mi oluyor? 20,000^2 bellek erişimleri vardır ve her bir önbellek bir bayan olsaydı, o Bayan başına yaklaşık 3.2 nanosaniye. (P4) üzerinde test ettim makine 3.2 GHz ve sanıyorum XP (ama bilmiyorum) 32 KB L1 önbellek ve 512 KB L2 var. 20,000 girişleri ile (80KB), L2 sayıda özlüyor yoktur sanırım. Bu (3.2*10^9 cycles/second) * 3.2*10^-9 seconds/miss) = 10.1 cycles/miss olur. Bana yüksek gibi görünüyor. Belki de değil, belki de matematiğim kötü. Ölçüm önbellek VTune ile özlüyor çalıştım ama bir BSOD aldım. Ve şimdi lisans sunucusuna bağlanmak için alamıyorum (grrrr).

typedef struct stItem
{
   long     lData;
   //char     acPad[20];
} LIST_NODE;



#if defined( WIN32 )
void StartTimer( LONGLONG *pt1 )
{
   QueryPerformanceCounter( (LARGE_INTEGER*)pt1 );
}

void StopTimer( LONGLONG t1, double *pdMS )
{
   LONGLONG t2, llFreq;

   QueryPerformanceCounter( (LARGE_INTEGER*)&t2 );
   QueryPerformanceFrequency( (LARGE_INTEGER*)&llFreq );
   *pdMS = ((double)( t2 - t1 ) / (double)llFreq) * 1000.0;
}
#else
// doesn't need 64-bit integer in this case
void StartTimer( LONGLONG *pt1 )
{
   // Just use clock(), this test doesn't need higher resolution
   *pt1 = clock();
}

void StopTimer( LONGLONG t1, double *pdMS )
{
   LONGLONG t2 = clock();
   *pdMS = (double)( t2 - t1 ) / ( CLOCKS_PER_SEC / 1000 );
}
#endif



long longrand()
{
   #if defined( WIN32 )
   // Stupid cheesy way to make sure it is not just a 16-bit rand value
   return ( rand() << 16 ) | rand();
   #else
   return rand();
   #endif
}

// get random value in the given range
int randint( int m, int n )
{
   int ret = longrand() % ( n - m   1 );
   return ret   m;
}

// I think I got this out of Programming Pearls (Bentley).
void ShuffleArray
(
   long *plShuffle,  // (O) return array of "randomly" ordered integers
   long lNumItems    // (I) length of array
)
{
   long i;
   long j;
   long t;

   for ( i = 0; i < lNumItems; i   )
      plShuffle[i] = i;

   for ( i = 0; i < lNumItems; i   )
      {
      j = randint( i, lNumItems - 1 );

      t = plShuffle[i];
      plShuffle[i] = plShuffle[j];
      plShuffle[j] = t;
      }
}



int main( int argc, char* argv[] )
{
   long          *plDataValues;
   LIST_NODE     *pstNodes;
   long          lNumItems = 20000;
   long          i, j;
   LONGLONG      t1;  // for timing
   double dms;

   if ( argc > 1 && atoi(argv[1]) > 0 )
      lNumItems = atoi( argv[1] );

   printf( "\n\n*** Testing %u nodes\n", lNumItems );

   srand( (unsigned int)time( 0 ));

   // allocate the nodes as one single chunk of memory
   pstNodes = (LIST_NODE*)malloc( lNumItems * sizeof( LIST_NODE ));
   assert( pstNodes != NULL );

   // Create an array that gives the access order for the nodes
   plDataValues = (long*)malloc( lNumItems * sizeof( long ));
   assert( plDataValues != NULL );

   // Access the data in order
   for ( i = 0; i < lNumItems; i   )
      plDataValues[i] = i;

   StartTimer( &t1 );

   // Loop through and access the memory a bunch of times
   for ( j = 0; j < lNumItems; j   )
      {
      for ( i = 0; i < lNumItems; i   )
         {
         pstNodes[plDataValues[i]].lData = i * j;
         }
      }

   StopTimer( t1, &dms );
   printf( "Total Ordered Time: %f\n", dms );

   // now access the array positions in a "random" order
   ShuffleArray( plDataValues, lNumItems );

   StartTimer( &t1 );

   for ( j = 0; j < lNumItems; j   )
      {
      for ( i = 0; i < lNumItems; i   )
         {
         pstNodes[plDataValues[i]].lData = i * j;
         }
      }

   StopTimer( t1, &dms );
   printf( "Total Random Time: %f\n", dms );

}

CEVAP
15 Temmuz 2009, ÇARŞAMBA


Süre veremem teklif bir cevap olsun ya da olmasın sayıların anlamı (değilim iyi usta önbellek gecikmeleri, ama rekoru ~10 döngüsü L1 önbellek özlüyor hemen hemen öyle), ben teklif Cachegrind gibi bir araç için yardım gerçekten görmek farklar önbellek performans arasında 2 testleri.

Cachegrind önbellek ve şube vurur Valgrind bir aracı (güçler her zaman güzel memcheck bu çerçeve)/özlüyor. Sen kaç/aslında programda alıyorsanız özlüyor bir fikir verecektir.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • DJAndrewRyan

    DJAndrewRyan

    22 Ocak 2007
  • Sali Kaceli

    Sali Kaceli

    24 ŞUBAT 2009
  • Sean Murphy

    Sean Murphy

    4 ŞUBAT 2009