整列したメモリを静的に確保する attribute ((aligned(n))
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
目次 |
基本的なaligned属性のつけかた
変数を確保するとき(Variable Attributes)か、型を宣言するとき(Type Attributes)に __attribute__((aligned(n))) をつけてaligned属性を付与します。 両者はほぼ同じ効果を持ちますが構造体の場合には異なる効果があります。これについては後述します。 以下の例文では n = 128 として128バイト境界に整列しています。
Variable Attributes
まず変数を確保するときにaligned属性をつける例を紹介します。 組み込み型や配列や構造体であっても同じ効果で、128バイトに整列した変数が得られます。
struct AAA;
int a __attribute__((aligned(128)));
int b[128] __attribute__((aligned(128));
AAA c __attribute__((aligned(128)));
int main (int argc, void* argv)
{
この場合は普通に128バイトに整列した a, b, c が得られます。
$ ./ppe.out &a = 0x10012180 &b = 0x10012380 &c = 0x10012200
Type Attributes
次に型を宣言するときにaligned属性をつける方法です。
typedef int aligned_int __attribute__((aligned(128)));
typedef int aligned_array_int[128] __attribute__((aligned(128)));
struct AAA { int a; } __attribute__((aligned(128)));
struct BBB { int a __attribute__((aligned(128))); };
aligned_int a;
aligned_array_int b;
AAA c;
BBB d;
構造体では構造体そのものにaligned属性をつけるか、そのメンバーにaligned属性をつけます。 結果はこのように128バイトに整列した変数が得られます。
$ ./ppe.out &a = 0x10012180 &b = 0x10012300 &c = 0x10012500 &d = 0x10012580
aligned属性を付けた構造体のサイズ
構造体そのもの、または構造体のメンバーにaligned属性をつけるとメモリに整列するだけでなく、 sizeof演算子の戻り値が変化します。 gccのマニュアルではaligned属性のついた構造体に対するsizeof演算子の振る舞いについて明確な記述がありません。 ここでは経験上得られた知識を元に記述します。
構造体のsizeof演算子の適用結果は、以下のルールに従うものと思われます。
- メンバーのaligned(n)と構造体そのものにつけたaligned(n)のうち、最大の n の倍数値になるように切り上げる。
例えば
struct AAA
{
int a;
int b __attribute__((aligned(16)));
};
この場合、構造体は16バイトに整列され、sizeof演算子の戻り値は32バイトになります。 これは構造体の先頭が16バイトに整列され、なおかつメンバーのbも16バイトに整列されるためです。 全体として16バイトの倍数値になるように切り上げられるので、合計で32バイトが構造体のサイズです。
$ ./ppe.out &a = 0x10012280, sizeof(a) = 32
2つ目の例を提示します。
struct BBB
{
int a;
int b __attribute__((aligned(16)));
} __attribute__((aligned(128)));
aligned(16)とaligned(128)のうち一番大きい n は 128 です。従って構造体の先頭は128バイトに整列されます。 メンバーのbは16バイトに整列されます。 全体として128バイトの倍数値になるように切り上げられるので、合計で128バイトが構造体のサイズです。
$ /ppe.out &b = 0x10012300, sizeof(b) = 128
構造体の型宣言ではなく構造体の実態を確保するときにaligned(n)を付けてもsizeofの戻り値は変化しません。
struct AAA
{
int a;
};
AAA a __attribute__((aligned(128)));
このようにsizeofの戻り値は4のままです。
./ppe.out &a = 0x10012180, sizeof(a) = 4
まとめ
構造体宣言に__attribute__((aligned(n)))をつけるとnバイトに整列し、サイズがnの倍数値に切り上げられます。これはメモリアドレスと転送サイズに制限のあるDMA転送では非常に役に立ちます。
aligned属性の制限事項
PowerPCアーキテクチャーにおいてスタックポインターは16の倍数になる事が保障されています。 従ってコンパイラは自動変数において16バイトまでは整列可能ですが、それ以上を整列させることは保証できません。 16バイト以上を指定してもコンパイラはエラーや警告を出さないので注意が必要です。 以下は正しくない例です。
int main (int argc, void** argv)
{
int a __attribute__((aligned(128)));
cout << "&a = " << &a << "\n";
実行結果はこのように16バイトには整列していますが128バイト境界に整列していません。
$ ./ppe.out &a = 0xfff7d440
