C言語のソースコードに
A=B=C=D=100;
のような書き方ありますよね。
コンパイル結果として下記のどれに相当でしょうか。
////////// (1)
A=100;
B=100;
C=100;
D=100;
////////// (2)
D = 100;
C = D;
B = C;
A = B;
(1)のほうが好ましいですが、
(2)には問題二つあります:
一つは頻繁にメモリをアクセスして遅い、
また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
それでは実際(1)と(2)のどっちでしょうか。
A=B=C=D=100; のような書き方はどうでしょうか
Re: A=B=C=D=100; のような書き方はどうでしょうか
コンパイラによると思いますが、A,B,C,Dが全てint型の変数であると仮定すると、gcc4.8.1では最適化オプションなし、-O2ともに(2)相当になりました。
実行したコマンド test.c
test.s
test_o2.s
実行したコマンド test.c
int A,B,C,D;
void test1(void) {
A=B=C=D=100;
}
void test2(void) {
A=100;
B=100;
C=100;
D=100;
}
void test3(void) {
D = 100;
C = D;
B = C;
A = B;
}
.file "test.c"
.comm _A, 4, 2
.comm _B, 4, 2
.comm _C, 4, 2
.comm _D, 4, 2
.text
.globl _test1
.def _test1; .scl 2; .type 32; .endef
_test1:
LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl $100, _D
movl _D, %eax
movl %eax, _C
movl _C, %eax
movl %eax, _B
movl _B, %eax
movl %eax, _A
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE0:
.globl _test2
.def _test2; .scl 2; .type 32; .endef
_test2:
LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl $100, _A
movl $100, _B
movl $100, _C
movl $100, _D
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE1:
.globl _test3
.def _test3; .scl 2; .type 32; .endef
_test3:
LFB2:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl $100, _D
movl _D, %eax
movl %eax, _C
movl _C, %eax
movl %eax, _B
movl _B, %eax
movl %eax, _A
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE2:
.ident "GCC: (GNU) 4.8.1"
.file "test.c"
.text
.p2align 4,,15
.globl _test1
.def _test1; .scl 2; .type 32; .endef
_test1:
LFB0:
.cfi_startproc
movl $100, _D
movl $100, _C
movl $100, _B
movl $100, _A
ret
.cfi_endproc
LFE0:
.p2align 4,,15
.globl _test2
.def _test2; .scl 2; .type 32; .endef
_test2:
LFB1:
.cfi_startproc
movl $100, _A
movl $100, _B
movl $100, _C
movl $100, _D
ret
.cfi_endproc
LFE1:
.p2align 4,,15
.globl _test3
.def _test3; .scl 2; .type 32; .endef
_test3:
LFB2:
.cfi_startproc
movl $100, _D
movl $100, _C
movl $100, _B
movl $100, _A
ret
.cfi_endproc
LFE2:
.comm _D, 4, 2
.comm _C, 4, 2
.comm _B, 4, 2
.comm _A, 4, 2
.ident "GCC: (GNU) 4.8.1"
ロックなど、他の対策を考えてください。みどり さんが書きました:また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
最後に編集したユーザー みけCAT on 2015年2月14日(土) 10:08 [ 編集 1 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: A=B=C=D=100; のような書き方はどうでしょうか
D = 100;
C = D;
B = C;
A = B;
です。
もし
int A, B, C, D;
だった場合、数値リテラルを代入するのであれば、
A=100;
B=100;
C=100;
D=100;
とした場合より遅いことはまず無いと思います。
ちょっと書き方を変えます。確かに、単純な命令数では多くなることも多いかもしれません。
しかし、レジスタアクセスや1クロックで済む命令などは、昨今では本当に誤差のレベルです。他の要因によってあっさりと逆転してしまうようなほどの軽微なものです。
メモリをアクセスして遅い、と言いますが、大抵のアーキテクチャでレジスタアクセスは1クロックレベルで超高速ですし、整数の変数であればコンパイラ次第でキャッシュを仕込むかもしれません。
コンパイラやコードの状況によっては最適化され、結果的に同じコードになることも多いはずです。「速くなると断言もできないし、遅くなる可能性すらある」ことです。
そのようなことを気にして、1のような定数ハードコーディングを行う事は、返ってプログラムの見通しや保守性を落とす結果を招くことがほとんどです。それでプログラムにバグが生まれれば本末転倒です。開発効率を犠牲にしてまでクロック単位で最適化をする開発など、それこそ天文学などの科学計算の分野か、よほど速度の出ない組み込み開発くらいです。
昔はそれが当たり前な時代もあったでしょうけども、今の時代でそれは稀なことです。
確かに実行コストの高い命令を気にしてコーディングすることはありますが、今回の件は過剰すぎます。最も高速な部類の命令すらネックになるのなら、根本的にそのプログラムの設計が間違っているか、スーパーコンピュータでも買うべきです。
もし他のスレッドから値が更新される可能性があるのであれば、排他制御を行えば良いだけの話です。それはマルチスレッドの問題であって、C言語の代入構文のせいではありません。
仮に他のスレッドからアクセスされる可能性があるのであれば、
A=100;
B=100;
C=100;
D=100;
と書いたとしても同様にデータレースの可能性があるからです。
(1)の方が好ましいというのは、勘違い、思い込みかと思われます。もし(1)がマルチスレッドで安全だと思ってコーディングしているのなら、そのコードではスレッドセーフではない可能性が高いです。
C = D;
B = C;
A = B;
です。
何を以って遅いといえるのでしょうか。実測したのでしょうか。一つは頻繁にメモリをアクセスして遅い、
もし
int A, B, C, D;
だった場合、数値リテラルを代入するのであれば、
A=100;
B=100;
C=100;
D=100;
とした場合より遅いことはまず無いと思います。
ちょっと書き方を変えます。確かに、単純な命令数では多くなることも多いかもしれません。
しかし、レジスタアクセスや1クロックで済む命令などは、昨今では本当に誤差のレベルです。他の要因によってあっさりと逆転してしまうようなほどの軽微なものです。
メモリをアクセスして遅い、と言いますが、大抵のアーキテクチャでレジスタアクセスは1クロックレベルで超高速ですし、整数の変数であればコンパイラ次第でキャッシュを仕込むかもしれません。
コンパイラやコードの状況によっては最適化され、結果的に同じコードになることも多いはずです。「速くなると断言もできないし、遅くなる可能性すらある」ことです。
そのようなことを気にして、1のような定数ハードコーディングを行う事は、返ってプログラムの見通しや保守性を落とす結果を招くことがほとんどです。それでプログラムにバグが生まれれば本末転倒です。開発効率を犠牲にしてまでクロック単位で最適化をする開発など、それこそ天文学などの科学計算の分野か、よほど速度の出ない組み込み開発くらいです。
昔はそれが当たり前な時代もあったでしょうけども、今の時代でそれは稀なことです。
確かに実行コストの高い命令を気にしてコーディングすることはありますが、今回の件は過剰すぎます。最も高速な部類の命令すらネックになるのなら、根本的にそのプログラムの設計が間違っているか、スーパーコンピュータでも買うべきです。
それは全く話の違う問題です。代入の問題ではありません。また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
もし他のスレッドから値が更新される可能性があるのであれば、排他制御を行えば良いだけの話です。それはマルチスレッドの問題であって、C言語の代入構文のせいではありません。
仮に他のスレッドからアクセスされる可能性があるのであれば、
A=100;
B=100;
C=100;
D=100;
と書いたとしても同様にデータレースの可能性があるからです。
(1)の方が好ましいというのは、勘違い、思い込みかと思われます。もし(1)がマルチスレッドで安全だと思ってコーディングしているのなら、そのコードではスレッドセーフではない可能性が高いです。
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: A=B=C=D=100; のような書き方はどうでしょうか
非常に有益な議論と教授をいただきまして、本当にいい勉強になりました。
これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
皆さん、有難うございました!!
これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
皆さん、有難うございました!!
Re: A=B=C=D=100; のような書き方はどうでしょうか
解決となっていますし,今まで投稿していない人間がしゃしゃり出てきて書くのもなんですが,結論の方向が明後日を向いているような気がしたので……。
そもそも,速度が出るようにアセンブリ言語で書こうとすると,対象プロセッサを決定し,そのプロセッサの特性を理解し,各命令がどのようにパイプラインを使うかも知った上で,その時点でのキャッシュがどうなっているかも勘案して実行順序も決めていく必要があります。
8086とかの牧歌的な時代ならクロックの総和である程度速度がわかりましたが,今どきのプロセッサはそう簡単に速度がわかる物ではないです。
また,
一応,x86系CPUにおいてはi486からCMPXCHG命令が追加されているので,Compare And Swapによるロックフリーアルゴリズムをこれにより作る,というのはできるかもしれませんが,それらは上位層において隠蔽される (e.g. InterlockedExchange (Windows), atomic_compare_exchange_strong (C11), std::atomic_compare_exchange_strong (C++11) etc.) ので,CPU命令を直接使う必要はないでしょう。
アセンブリ言語の勉強よりも,nullptrさんの投稿 (特に前段) をちゃんと理解した方がよいかと思いますよ。みどり さんが書きました:これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
そもそも,速度が出るようにアセンブリ言語で書こうとすると,対象プロセッサを決定し,そのプロセッサの特性を理解し,各命令がどのようにパイプラインを使うかも知った上で,その時点でのキャッシュがどうなっているかも勘案して実行順序も決めていく必要があります。
8086とかの牧歌的な時代ならクロックの総和である程度速度がわかりましたが,今どきのプロセッサはそう簡単に速度がわかる物ではないです。
また,
みけCAT さんが書きました:ロックなど、他の対策を考えてください。みどり さんが書きました:また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
とお二方ともから指摘されているとおり,スレッド間でのアクセス競合の問題はアセンブリ言語を勉強したところでどうにかなるものではないです。nullptr さんが書きました:それは全く話の違う問題です。代入の問題ではありません。また順番にD,C,Bをアクセスしなければならないので、その内に他のthreadにD,C,Bのどれかを別の値で更新しちゃう可能性もあるので、
データの整合性問題が起きます。
もし他のスレッドから値が更新される可能性があるのであれば、排他制御を行えば良いだけの話です。それはマルチスレッドの問題であって、C言語の代入構文のせいではありません。
一応,x86系CPUにおいてはi486からCMPXCHG命令が追加されているので,Compare And Swapによるロックフリーアルゴリズムをこれにより作る,というのはできるかもしれませんが,それらは上位層において隠蔽される (e.g. InterlockedExchange (Windows), atomic_compare_exchange_strong (C11), std::atomic_compare_exchange_strong (C++11) etc.) ので,CPU命令を直接使う必要はないでしょう。
Re: A=B=C=D=100; のような書き方はどうでしょうか
…どうしてそうなったんでしょう…?みどり さんが書きました:これからはアセンブラ言語を勉強して、さらに研究していこうと思います。
別にアセンブラがやりたいならやめろとは言いませんけど、もしも、アセンブラを自分で書けば速くなると思っているのなら、大間違いです。
気をつけてください。
最後に編集したユーザー nullptr on 2015年2月17日(火) 18:26 [ 編集 4 回目 ]
✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: A=B=C=D=100; のような書き方はどうでしょうか
ある処理の仕方が遅いかどうかを議論するときは、推測をするだけではなく、
実験をしたりデータシートなどで調べたりしてください。
もちろん実験の結果は環境依存ですが、全く根拠がない推測よりはマシだと思います。
実験をしたりデータシートなどで調べたりしてください。
もちろん実験の結果は環境依存ですが、全く根拠がない推測よりはマシだと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)