SORU
26 Aralık 2013, PERŞEMBE


C 11 bellek hizalamak için önerilen yol nedir

Tek yapımcı, tek tüketici halka arabelleği bir uygulama üzerinde çalışıyorum.İki koşul var:

1) tek bir yığın önbellek satırı için halka arabelleği örneği ayrılan Hizalayın.

2) önbellek satırı için halka arabelleği içinde bir alan (yanlış paylaşım önlemek için) Hizalayın.

Dersim gibi bir şey görünüyor:

#define CACHE_LINE_SIZE 64  // To be used later.

template<typename T, uint64_t num_events>
class RingBuffer {  // This needs to be aligned to a cache line.
public:
  ....

private:
  std::atomic<int64_t> publisher_sequence_ ;
  int64_t cached_consumer_sequence_;
  T* events_;
  std::atomic<int64_t> consumer_sequence_;  // This needs to be aligned to a cache line.

};

Bana gelin 1 yani ilk duralımtek bir yığın ayrılan örneği hizalamasınıf. Birkaç yolu vardır:

1) c 11 alignas(..) belirleyicisi Kullanın:

template<typename T, uint64_t num_events>
class alignas(CACHE_LINE_SIZE) RingBuffer {
public:
  ....

private:
  // All the private fields.

};

2) sınıf tanımını değiştirmeden posix_memalign(..) yerleştirme new(..) Kullanın. Bu platform bağımsız olması değil muzdarip:

 void* buffer;
 if (posix_memalign(&buffer, 64, sizeof(processor::RingBuffer<int, kRingBufferSize>)) != 0) {
   perror("posix_memalign did not work!");
   abort();
 }
 // Use placement new on a cache aligned buffer.
 auto ring_buffer = new(buffer) processor::RingBuffer<int, kRingBufferSize>();

3) GCC/Çınlama uzantısı __attribute__ ((aligned(#))) Kullanın

template<typename T, uint64_t num_events>
class RingBuffer {
public:
  ....

private:
  // All the private fields.

} __attribute__ ((aligned(CACHE_LINE_SIZE)));

4) posix_memalign(..) yerine ** 15 C 11 standart fonksiyonunu kullanmaya çalıştım ama Ubuntu 12.04 üzerinde GCC 4.8.1 stdlib.h tanım bulamadı

Bunların hepsi aynı şeyi yapmak için garantili? Amacım hizalama (iki kelime) bazı sınırı vardır. herhangi bir yöntem değil, bu yüzden önbellek-çizgi çizilir. alignas(..) standart kullanarak işaret eden Platform bağımsız ikincil bir hedeftir.

alignas(..) __attribute__((aligned(#))) makinede önbellek sınırının altında olabilecek bazı sınırı olup olmadığı konusunda net değilim. Bu artık sunamayacağı ama baskı adresleri hep 64 alamadım düşünürken alignas(..) ile uyumlu adresler bayt. Tam tersine posix_memalign(..) Her zaman işe yaramıştır. Yine belki de hata yapmaktan sıkıldım artık bunu daha fazla sunamayacağı.

İkinci hedef almaktırsınıf/a yapı içinde bir alan hizalayınönbellek satırı için. Bu yanlış paylaşım önlemek için yapıyorum. Aşağıdaki yolları denedim:

1) C 11 alignas(..) belirleyicisi Kullanın:

template<typename T, uint64_t num_events>
class RingBuffer {  // This needs to be aligned to a cache line.
  public:
  ...
  private:
    std::atomic<int64_t> publisher_sequence_ ;
    int64_t cached_consumer_sequence_;
    T* events_;
    std::atomic<int64_t> consumer_sequence_ alignas(CACHE_LINE_SIZE);
};

2) GCC/Çınlama uzantısı __attribute__ ((aligned(#))) Kullanın

template<typename T, uint64_t num_events>
class RingBuffer {  // This needs to be aligned to a cache line.
  public:
  ...
  private:
    std::atomic<int64_t> publisher_sequence_ ;
    int64_t cached_consumer_sequence_;
    T* events_;
    std::atomic<int64_t> consumer_sequence_ __attribute__ ((aligned (CACHE_LINE_SIZE)));
};

Bu yöntemler, consumer_sequence önbellek şekilde olsun 64 bayt nesne başladıktan sonra bir adrese consumer_sequence Hizala gibi görünebilir önbellek uyumlu nesnesi bağlıdır. Benim sorum burada - daha iyi yollar aynı şeyi var mı?

DÜZENLEME: Nedeni aligned_alloc makinem eglibc üzerinde 2.15 (Ubuntu 12.04) olmasıydı üzerinde işe yaramadı. Eglibc daha yeni bir sürümü üzerinde çalıştı.

man pagegelen: The function aligned_alloc() was added to glibc in version 2.16.

Bu eglibc/abone olarak giriş bu son sürümü gerekir edemem beri benim için oldukça işe yaramaz hale getirir.

CEVAP
26 Aralık 2013, PERŞEMBE


Ne yazık ki bulduğum en iyi ekstra alan ayırmak ve ardından "" bölümü. hizalanmış kullanıyor Bu RingBuffer new ekstra 64 bayt isteği ve ilk 64byte bunun bir parçası hizalanmış dönün. Alan atıkların ama ihtiyacınız uyum sağlayacaktır. Muhtemelen unallocate fiili tahsis adresi döndürdü önce hafızayı ayarlamak gerekir.

[Bellek geri döndü][bellek başlamak için pointer][memory uyumlu][ek hafıza]

(RingBuffer hiçbir inheritence varsayarak)gibi bir şey

void * RingBuffer::operator new(size_t request)
{
     static const size_t ptr_alloc=sizeof(void *);
     static const size_t align_size=64;
     static const size_t request_size=sizeof(RingBuffer) align_size;
     static const size_t needed = ptr_alloc request_size;

     void * alloc=::operator new(needed);
     void *ptr=std::align(align_size, sizeof(RingBuffer),
                          alloc ptr_alloc, request_size);

     ((void **)ptr)[-1]=alloc; // save for delete calls to use
     return ptr;  
}

void RingBuffer::operator delete(void * ptr)
{
    if (ptr) // 0 is valid, but a noop, so prevent passing negative memory
    {
           void * alloc=((void **)ptr)[-1];
           ::operator delete (alloc);
    }
}

İkinci şartı olan bir veri üyesi RingBuffer ayrıca 64byte uyumlu, bunu bilmek Başlat this uyumlu, pad zorlamak uyum için veri üyeleri.

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Kenneth Håkonsen

    Kenneth Håk

    13 Mart 2011
  • parlophone

    parlophone

    28 ŞUBAT 2006
  • Within Temptation

    Within Tempt

    18 EYLÜL 2006