5 Mayıs 2020 Salı

Data Alignment

Giriş
Ne C dilinde ne de C++ standardında alignment'la ilgili bir madde bulunmuyor. Alignment tamamen derleyicinin bildiği bir şey. Aynı derleyiciyi kullanırsak, C veya C++ için yapılan alignment arasında bir fark yok. Örneğin GCC, her iki dil için de aynı kuralları işletiyor. Dolayısıyla iki dil arasında sorun çıkmıyor.

Derleyici Alanların Yerini Değiştiremez
Açıklaması şöyle.
The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier),...
C++17 için açıklama şöyle. Bu şu anlama geliyor static olmayan ve aynı access modifier'a sahip iki tane alan olsun. Bunların isimleri field1 ve field2 olsun. field1 değişkenin bellekte field2'den önce gelmek zorunda. Farklı access modier'lar sahip alanlar için bir açıklama yok.
Non-static data members of a (non-union) class with the same access control (Clause 14) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified.
Örnek
Elimizde şöyle bir kod olsunn
struct A { int x, y, z; } a;
struct F { public: int p; private: int q; public: int r; } f;
Açıklaması şöyle.
According to the above standard text, C++17 guaranteed &a.x < &a.y, &a.y < &a.z, and &f.p < &f.r (but did NOT guarantee &f.p < &f.q, ...).
Data Alignment Neden Lazım
Tüm cevap optimizasyonda yatıyor. Donanımlar örneğin double gibi bir değeri eğer veri bellekte hizalı ise tek bir işlem ile okuyabilir. Ancak hizalı değilse daha fazla işlem kullanır. Aşağıdaki örnekte hizalı veriye bir seferde erişim gösterilmiş.
+-------------------------+-------------------------+
| XX XX XX XX XX XX XX XX | 12 34 56 78 90 ab cd ef |
+-------------------------+-------------------------+
                           ^-----------------------^
                                     Cycle 1
Bir diğer örnekte ise hizalı olmayan veriye iki işlem ile erişim gösteriliyor.
+-------------------------+-------------------------+
| XX XX XX XX XX 12 34 56 | 78 90 ab cd ef XX XX XX |
+-------------------------+-------------------------+
                ^--------^ ^--------------^
                  Cycle 1      Cycle 2
Bellekten israf ederek hızı artırmak için Data Alignment (Veri Hizalaması) yöntemi geliştirilmiştir. Derleyici veriyi en hızlı erişebileceği şekilde hizalar, gerekirse araya boşluklar (padding) ekler.

Alignment için Kural
Açıklaması şöyle
In a standard-compliant† compiler the following hold:

(1) arrays cannot have any padding between elements, due to the way they can be accessed with pointersref;
(2) standard layout structs may or may not have padding after each member, but not at the beginning, because they are layout-compatible with "shorter"-but-equal standard layout structsref;
(3) array elements and struct members are properly alignedref;

Diğer kurallar evrensel değildir. Derleyicisine göre değişir. Gördüklerim şöyle:

- Alignment için genellikle en büyük alanın (size of largest member) büyüklüğü seçilir.

Eğer bellek az ise alanların yerleri değiştirilerek daha az bellek kullanılabilir.
{char a; long b; char c; long d; char e; char f; } //is 18 bytes, 
{char a; char c; char d; char f; long b; long d; } //is 12 bytes.

Struct ve Data Alignment
Örnek
Elimizde şöyle bir kod olsun
struct S {
  int a[4];
  int b[4];
} s;
b alanına yazmak için a alanının dışına taşma yöntemi kullanılamaz. Şu kod yanlış.
s.a[6] = 2;
Çünkü struct bellekte şöyle olmuş olabilir.
instance of struct:
+-----------+----------------+-----------+---------------+
|  array a  |  maybe padding |  array b  | maybe padding |
+-----------+----------------+-----------+---------------+
Flexible Array Member
Flexible Array Member yazısına taşıdım.

Alignment ve Bitfield
Örnekte bitfield alan 1 byte tutması gerekirken (sizeof () 9 byte vermeli) 16 byte tutuyor.
struct {
        int a : 1; // bit field sized 1
        double b;
    }structVar;
Alignment ve Kalıtım
Eğer alt sınıf data structure  alignment'a tabi tutulursa - örneğin son elemandan sonra padding yapılırsa - kalıtan sınıfın eklediği yeni alanlar pad'lenen alana yerleştirilmeye çalışılır. Örnek'te her iki sınıfın da sizeof() ile alınan büyüklükleri 24 çıkıyor.
class Base
{
private:
  double d;
protected:
  long l;
public:
  int i;
};

class Derived : public Base
{
private:
  float f;
};
Stack Alignment
Derleyici stack alignment yapabilir.

Hiç yorum yok:

Yorum Gönder