關于如何將結構與快取行對齊(例如,
其中上面的框是快取行,其他框是我們的小結構的實體。
- 我真的想要這個嗎?我無法真正解決這個問題。通常,我們說如果我們將結構與快取行大小對齊,訪問會更快,因為我們只需要加載單個快取行。但是,看到我的例子,我想知道這是否真的是真的。不對齊會不會更快,而是在單個快取行中存盤更多實體?
Thank you so much for your input here. It is much appreciated.
uj5u.com熱心網友回復:
為了解決 (2),尚不清楚使用打包結構的額外開銷(例如,未對齊的 64 位訪問)和訪問陣列元素的額外數學運算是否值得。但是如果你想嘗試一下,你可以創建一個新的結構來適當地打包你的結構元素,然后創建一個小的包裝類來訪問元素,就像你訪問陣列一樣:
#include <array>
#include <iostream>
using namespace std;
template <typename T, size_t BlockAlignment>
struct __attribute__((packed)) Packer
{
static constexpr size_t NUM_ELEMS = BlockAlignment / sizeof(T);
static_assert( NUM_ELEMS > 0, "BlockAlignment too small for one object." );
T &operator[]( size_t index ) { return packed[index]; }
T packed[ NUM_ELEMS ];
uint8_t padding[ BlockAlignment - sizeof(T)*NUM_ELEMS ];
};
template <typename T, size_t NumElements, size_t BlockAlignment>
struct alignas(BlockAlignment) PackedAlignedArray
{
typedef Packer<T, BlockAlignment> PackerType;
std::array< PackerType, NumElements / PackerType::NUM_ELEMS 1 > packers;
T &operator[]( size_t index ) {
return packers[ index / PackerType::NUM_ELEMS ][ index % PackerType::NUM_ELEMS ];
}
};
struct __attribute__((packed)) Foo
{
uint64_t a;
uint64_t b;
uint8_t c;
};
int main()
{
static_assert( sizeof(Foo) == 17, "Struct not packed for test" );
constexpr size_t NUM_ELEMENTS = 10;
constexpr size_t BLOCK_ALIGNMENT = 64;
PackedAlignedArray<Foo, NUM_ELEMENTS, BLOCK_ALIGNMENT> theArray;
for ( size_t i=0; i<NUM_ELEMENTS; i )
{
// Display the memory offset between the current
// element and the start of the array
cout << reinterpret_cast<std::ptrdiff_t>(&theArray[i]) -
reinterpret_cast<std::ptrdiff_t>(&theArray[0]) << std::endl;
}
return 0;
}
程式的輸出顯示了 17 位元組元素在記憶體中地址的位元組偏移量,每四個元素自動重置為 64 的倍數:
0
17
34
64
81
98
128
145
162
192
uj5u.com熱心網友回復:
您可以通過使用 GNU C 或其他方式將結構本身宣告為欠對齊來打包到快取行中__attribute__((packed)),因此它具有 sizeof(struct) = 17 而不是通常的填充,您可以使結構大小成為 8 的倍數位元組(假設 alignof(uint64_t) == 8,由于具有 uint64_t 成員,它通常具有的對齊方式)。
然后把它放在一個 中alignas(256) T array[],所以只有陣列的開頭是對齊的。
對齊比結構物件本身更寬的邊界只有在包含多個結構的更大物件方面才有可能;ISO C 的對齊系統不能指定一個物件只能進入從某個對齊邊界開始的容器中;這將導致荒謬的情況,例如T *arr成為有效陣列的開頭,但arr 1不是有效陣列,即使它具有相同的型別。
除非您擔心兩個執行緒之間的錯誤共享,否則您最多應該自然對齊您的結構,例如 32 位元組。自然對齊的物件 (alignof=sizeof) 不能跨越大于自身的對齊邊界。但這會浪費很多空間,所以最好讓編譯器將其對齊 8,繼承alignof(struct)= max (alignof(members))。
另請參閱如何組織結構中的成員以在對齊上浪費最少的空間?有關單個結構內的空間如何作業的更多詳細資訊。
根據訪問資料的方式,一種選擇是將一對存盤uint64_t在一個陣列中,并將相應的位元組存盤在一個單獨的陣列中。 這樣你就沒有填充位元組,一切都是 2 大小和對齊的冪。但是隨機訪問所有 3 個相互配合的成員可能會花費 2 次快取未命中而不是 1 次。
但是對于按順序迭代您的資料,這非常好。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/441491.html
標籤:c caching memory cpu-architecture memory-alignment
