アラインメントの効果は本当?
-
菅沢
アラインメントの効果は本当?
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[n];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];
int i = (int)a[0];
char c = a[sizeof(int)];
double d = (double)a[sizeof(int)+13];
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[n];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];
int i = (int)a[0];
char c = a[sizeof(int)];
double d = (double)a[sizeof(int)+13];
Re: 菅沢
アラインメントの効果は本当? さんが書きました:int i = s.no;
char c = s.name[n];
double d = s.average;
この2個のコードは同じ働きではありません。アラインメントの効果は本当? さんが書きました:char a[sizeof(int)+13+sizeof(double)];
int i = (int)a[0];
char c = a[sizeof(int)];
double d = (double)a[sizeof(int)+13];
よって比較は意味がないのではないでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
-
菅沢
Re: 菅沢
ごめんなさい!!
出直します。
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[0];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];
int i = (int)a[0];
char c = a[sizeof(int)];
double d = (double)a[sizeof(int)+13];
出直します。
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[0];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];
int i = (int)a[0];
char c = a[sizeof(int)];
double d = (double)a[sizeof(int)+13];
Re: 菅沢
最初の書き込みと「出直し」た書き込み、文章が全く同じですね。
きついことを言って申し訳ありませんが、出直した意味が全くありません。
きついことを言って申し訳ありませんが、出直した意味が全くありません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
-
菅沢
再度出直します
再度出直します[何度も何度もほんとうに悪かったのです!]
========================================================================
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[0];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];// さらにこの中にint data 先頭に一つ、そのつぎにchar 13個、それからdouble 一つ設定済みと仮定
int i = *(int&)a;
char c = a[sizeof(int)];
double d = *(double&)(a + sizeof(int) + 13);
========================================================================
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[0];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];// さらにこの中にint data 先頭に一つ、そのつぎにchar 13個、それからdouble 一つ設定済みと仮定
int i = *(int&)a;
char c = a[sizeof(int)];
double d = *(double&)(a + sizeof(int) + 13);
Re: 菅沢
このケースであれば,アライメントされている方が速くなる可能性が高いと思いますね.
配列aを使う後者の方は,CPUによっては例外が発生して動かない場合もあると思います.
参考:http://www5d.biglobe.ne.jp/~noocyte/Pro ... nment.html
配列aを使う後者の方は,CPUによっては例外が発生して動かない場合もあると思います.
参考:http://www5d.biglobe.ne.jp/~noocyte/Pro ... nment.html
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: 菅沢
三度とも内容は何も変わっていません。それとcodeタグをご利用下さい。 → http://dixq.net/board/board.html#k10
一般論としてアライメントされている方が早い可能性がありますが、今時のCPUはデータ・キャッシュされるので差がない可能性の方が大きいです。
ただ、今のコードはみなさんが書かれている通り等価な処理ではないので比較対象として不的確な上にコンパイルエラーまで出ます。
環境依存ですが、VC++の場合
#pragma pack(1)
でアライメントを変更可能ですので、そちらを使って同じ形の構造体を使って比較した方が良いと思います。
一般論としてアライメントされている方が早い可能性がありますが、今時のCPUはデータ・キャッシュされるので差がない可能性の方が大きいです。
ただ、今のコードはみなさんが書かれている通り等価な処理ではないので比較対象として不的確な上にコンパイルエラーまで出ます。
環境依存ですが、VC++の場合
#pragma pack(1)
でアライメントを変更可能ですので、そちらを使って同じ形の構造体を使って比較した方が良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
菅沢
アラインメントの効果は本当?
みなさんいろいろご教授ありがとうございます。
最後の出直し[今度こそ!]----本当に申し訳ございませんでした
========================================================================
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
最後の出直し[今度こそ!]----本当に申し訳ございませんでした
========================================================================
便利さと関係なく、単純にアクセス速度を考えたいです。
理論上(一般論)として、下記の例で言えば、
アラインメントのお陰で、早くなるかどうか[実際は処理系に依存かもしれないですが]。
struct st {
int no;
char name[13];
double average;
} s;
アラインメントのお陰で、
int i = s.no;
char c = s.name[0];
double d = s.average;
は下記のケースと比べば、アクセス速度が早いのでしょうか。
char a[sizeof(int)+13+sizeof(double)];// さらにこの中にint data 先頭に一つ、そのつぎにchar 13個、それからdouble 一つ設定済みと仮定
int i = *(int*)a;
char c = a[sizeof(int)];
double d = *(double*)(a + sizeof(int) + 13);
Re: 菅沢
そんなに拘るのなら、ご自分で実際に計測されてはいかかでしょうか?
-
管沢
アラインメントの効果は本当?
一般的な結論というか理論的な見地からの情報を得たいですね。h2so5 さんが書きました:そんなに拘るのなら、ご自分で実際に計測されてはいかかでしょうか?
いまはCテキストを読むだけが、この後実機練習しようとしています。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: 菅沢
こういう物は環境を限定しないと成立しないので環境を限定します。それでもINTELのCPUだとしても型番で動作が異なる可能性があります。あるいはコンパイラ毎に機械語コードも変わります。
機械語コードが同じでもCPU種類毎に動作が異なる可能性があり論理的予想は外れる可能性があるので、論理的予想は大体の場合無意味です。なので実測に基づいた方がより建設的です。
[補足]推測を立てて実測することは有意義ですが、推測だけで延々話していても現実は違うかも知れません。ぜひ推測の上実測されることをお勧めします。
機械語コードが同じでもCPU種類毎に動作が異なる可能性があり論理的予想は外れる可能性があるので、論理的予想は大体の場合無意味です。なので実測に基づいた方がより建設的です。
[補足]推測を立てて実測することは有意義ですが、推測だけで延々話していても現実は違うかも知れません。ぜひ推測の上実測されることをお勧めします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: 菅沢
ちなみに、このコード自体を最大最適化レベルでコンパイルすると
環境:cygwin コンパイラ:gcc 最適化:-O3
アセンブルコードは、最適化されすぎて意味のないコードになります。
長いので一旦分けます。
環境:cygwin コンパイラ:gcc 最適化:-O3
#include <stdio.h>
#include <time.h>
// 構造体を利用。
struct st {
int no;
char name[13];
double average;
} s = {0};
char array[sizeof(int)+13+sizeof(double)];
void subA(int loops)
{
int i,c,d,l;
for( l=0 ; l<loops ; l++ ) {
i = s.no;
c = s.name[0];
d = s.average;
}
}
void subB(int loops)
{
int i,c,d,l;
// 配列を強引にアクセス
for( l=0 ; l<loops ; l++ ) {
i = *(int*)array;
c = array[sizeof(int)];
d = *(double*)(array + sizeof(int) + 13);
}
}
int main(){
int ms1,ms2;
struct timespec ts;
// 計測A
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subA(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time A: %dms\n", ms2-ms1);
// 計測B
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subB(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time B: %dms\n", ms2-ms1);
return 0;
} .file "a.c"
.text
.p2align 4,,15
.globl _subA
.def _subA; .scl 2; .type 32; .endef
_subA:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
.p2align 4,,15
.globl _subB
.def _subB; .scl 2; .type 32; .endef
_subB:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "time A: %dms\12\0"
LC1:
.ascii "time B: %dms\12\0"
.text
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
subl $56, %esp
movl %edi, -4(%ebp)
leal -24(%ebp), %edi
movl %ecx, -16(%ebp)
movl %ebx, -12(%ebp)
movl %esi, -8(%ebp)
call ___main
movl %edi, 4(%esp)
movl $1, (%esp)
call _clock_gettime
movl -20(%ebp), %ebx
movl -24(%ebp), %esi
movl %edi, 4(%esp)
movl $1, (%esp)
call _clock_gettime
movl -20(%ebp), %eax
imull $1000, %esi, %esi
movl %eax, -36(%ebp)
movl $1125899907, %eax
imull -36(%ebp)
imull $1000, -24(%ebp), %eax
sarl $31, -36(%ebp)
sarl $18, %edx
subl -36(%ebp), %edx
movl $LC0, (%esp)
leal (%edx,%eax), %ecx
movl $1125899907, %eax
imull %ebx
sarl $31, %ebx
sarl $18, %edx
subl %ebx, %edx
subl %edx, %ecx
subl %esi, %ecx
movl %ecx, 4(%esp)
call _printf
movl %edi, 4(%esp)
movl $1, (%esp)
call _clock_gettime
movl -20(%ebp), %ebx
movl -24(%ebp), %esi
movl %edi, 4(%esp)
movl $1, (%esp)
call _clock_gettime
movl -20(%ebp), %edi
movl $1125899907, %eax
imull $1000, %esi, %esi
imull %edi
imull $1000, -24(%ebp), %eax
sarl $31, %edi
movl $LC1, (%esp)
sarl $18, %edx
subl %edi, %edx
leal (%edx,%eax), %ecx
movl $1125899907, %eax
imull %ebx
subl %esi, %ecx
sarl $31, %ebx
movl %edx, %esi
sarl $18, %esi
subl %ebx, %esi
subl %esi, %ecx
movl %ecx, 4(%esp)
call _printf
movl -16(%ebp), %ecx
xorl %eax, %eax
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
movl %ebp, %esp
popl %ebp
leal -4(%ecx), %esp
ret
.globl _s
.bss
.align 32
_s:
.space 32
.comm _array, 25, 0
.def _clock_gettime; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: アラインメントの効果は本当?
じゃあ最適化しないとどうなるかと言うと、
優位な差は認められません。CPUのデータキャッシュが働きまくっているので意味が無いといえば意味のないコードです。
アセンブラコード自体はsubBの方がわずかに長いんですけどね。
アセンブラコード自体はsubBの方がわずかに長いんですけどね。
_subA:
pushl %ebp
movl %esp, %ebp
subl $20, %esp
movl $0, -4(%ebp)
jmp L2
L3:
movl _s, %eax
movl %eax, -16(%ebp)
movzbl _s+4, %eax
movsbl %al,%eax
movl %eax, -12(%ebp)
fldl _s+24
fnstcw -18(%ebp)
movzwl -18(%ebp), %eax
movb $12, %ah
movw %ax, -20(%ebp)
fldcw -20(%ebp)
fistpl -8(%ebp)
fldcw -18(%ebp)
addl $1, -4(%ebp)
L2:
movl -4(%ebp), %eax
cmpl 8(%ebp), %eax
jl L3
leave
ret
_subB:
pushl %ebp
movl %esp, %ebp
subl $20, %esp
movl $0, -4(%ebp)
jmp L6
L7:
movl $_array, %eax
movl (%eax), %eax
movl %eax, -16(%ebp)
movzbl _array+4, %eax
movsbl %al,%eax
movl %eax, -12(%ebp)
movl $_array+17, %eax
fldl (%eax)
fnstcw -18(%ebp)
movzwl -18(%ebp), %eax
movb $12, %ah
movw %ax, -20(%ebp)
fldcw -20(%ebp)
fistpl -8(%ebp)
fldcw -18(%ebp)
addl $1, -4(%ebp)
L6:
movl -4(%ebp), %eax
cmpl 8(%ebp), %eax
jl L7
leave
ret
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
菅沢
Re: アラインメントの効果は本当?
softya(ソフト屋)様
いつもお世話になっております。
実験コードまで組んでいただき本当にありがとうございます。
うしろのマシンコード分りませんが、C言語の部分ではi,c,d 三つの変数を全部 int 型に定義されていますね、
これで、アラインメントの性格から生まれた両者(構造体アクセスと配列アクセス)の差は分らなくなるのではないでしょうか 。
即ち、下記のようにi,c,d をそれぞれ int, char, double 型にしなければ、この実験は無意味になるかな。?
いつもお世話になっております。
実験コードまで組んでいただき本当にありがとうございます。
うしろのマシンコード分りませんが、C言語の部分ではi,c,d 三つの変数を全部 int 型に定義されていますね、
これで、アラインメントの性格から生まれた両者(構造体アクセスと配列アクセス)の差は分らなくなるのではないでしょうか 。
即ち、下記のようにi,c,d をそれぞれ int, char, double 型にしなければ、この実験は無意味になるかな。?
#include <stdio.h>
#include <time.h>
// 構造体を利用。
struct st {
int no;
char name[13];
double average;
} s = {0};
char array[sizeof(int)+13+sizeof(double)];
void subA(int loops)
{
int i,c,d,l;
for( l=0 ; l<loops ; l++ ) {
int i = s.no;
char c = s.name[0];
double d = s.average;
}
}
void subB(int loops)
{
int i,c,d,l;
// 配列を強引にアクセス
for( l=0 ; l<loops ; l++ ) {
int i = *(int*)array;
char c = array[sizeof(int)];
double d = *(double*)(array + sizeof(int) + 13);
}
}
int main(){
int ms1,ms2;
struct timespec ts;
// 計測A
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subA(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time A: %dms\n", ms2-ms1);
// 計測B
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subB(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time B: %dms\n", ms2-ms1);
return 0;
}
Re: アラインメントの効果は本当?
そんなことないと思います.菅沢 さんが書きました: うしろのマシンコード分りませんが、C言語の部分ではi,c,d 三つの変数を全部 int 型に定義されていますね、
これで、アラインメントの性格から生まれた両者(構造体アクセスと配列アクセス)の差は分らなくなるのではないでしょうか 。
即ち、下記のようにi,c,d をそれぞれ int, char, double 型にしなければ、この実験は無意味になるかな。?
結局配列aにアクセスするときはアライメントされていないアドレスへアクセスするわけですから.
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: アラインメントの効果は本当?
[追記]申し訳ないですが、菅沢さんと言う方に心当たりがありません。名前を統一していただけると過去の話とつながるのですが・・・。
失礼しました。書き換え間違いですね。
$ ./a
time A: 26ms
time B: 32ms
差は出ましたが問題はsubAとsubBでアセンブラレベルのプログラムコードが違うということです。
subAではループ内が7命令。subBでは9命令でメモリアクセスも増えています。
これを同じにしないとアライメントの差を比較することが出来ません。
失礼しました。書き換え間違いですね。
$ ./a
time A: 26ms
time B: 32ms
差は出ましたが問題はsubAとsubBでアセンブラレベルのプログラムコードが違うということです。
subAではループ内が7命令。subBでは9命令でメモリアクセスも増えています。
これを同じにしないとアライメントの差を比較することが出来ません。
#include <stdio.h>
#include <time.h>
// 構造体を利用。
struct st {
int no;
char name[13];
double average;
} s = {0};
// 配列を強引にアクセス
char array[sizeof(int)+13+sizeof(double)] = {0};
void subA(int loops)
{
int i,l;
char c;
double d;
// 構造体をアクセス
for( l=0 ; l<loops ; l++ ) {
i = s.no;
c = s.name[0];
d = s.average;
}
}
void subB(int loops)
{
int i,l;
char c;
double d;
// 配列を強引にアクセス
for( l=0 ; l<loops ; l++ ) {
i = *(int*)array;
c = array[sizeof(int)];
d = *(double*)(array + sizeof(int) + 13);
}
}
int main(){
int ms1,ms2;
struct timespec ts;
// 計測A
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subA(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time A: %dms\n", ms2-ms1);
// 計測B
clock_gettime(CLOCK_REALTIME, &ts);
ms1 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
subB(10000000);
clock_gettime(CLOCK_REALTIME, &ts);
ms2 = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf("time B: %dms\n", ms2-ms1);
return 0;
}
_subA:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
movl $0, -16(%ebp)
jmp L2
L3:
movl _s, %eax
movl %eax, -20(%ebp)
movzbl _s+4, %eax
movb %al, -9(%ebp)
fldl _s+24
fstpl -8(%ebp)
addl $1, -16(%ebp)
L2:
movl -16(%ebp), %eax
cmpl 8(%ebp), %eax
jl L3
leave
ret_subB:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
movl $0, -16(%ebp)
jmp L6
L7:
movl $_array, %eax
movl (%eax), %eax
movl %eax, -20(%ebp)
movzbl _array+4, %eax
movb %al, -9(%ebp)
movl $_array+17, %eax
fldl (%eax)
fstpl -8(%ebp)
addl $1, -16(%ebp)
L6:
movl -16(%ebp), %eax
cmpl 8(%ebp), %eax
jl L7
leave
ret
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。