teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

考察に誤りがあるので訂正

2017/12/23 01:30

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -1,3 +1,20 @@
1
+ ベストアンサーを戴きましたが、不注意で誤った考察をしました。考察に使うべきコードと結果は、strike君が示したものではなく、asmさんの[「なおしてみました」](https://wandbox.org/permlink/sWnByHBlG99FV9Oj)のほうだと思います。その結果は、こうです。
2
+
3
+ 8bit[1]整数の処理時間 = 0.587834秒
4
+ 16bit[2]整数の処理時間 = 0.585182秒
5
+ 32bit[4]整数の処理時間 = 0.580845秒
6
+ 64bit[8]整数の処理時間 = 1.405345秒
7
+
8
+ 8〜32bitが横並び、64bitは2.4倍の時間が掛かっている。私の手元でも同様の結果になりました(ただ古いパソコンのせいか、2.4倍ではなく3倍超orz)。不適切なコードの実験は無意味です。まず、strike君はobjdumpも含めて自分の手元でやり直して、結果を見直すべきです。
9
+
10
+ この結果から、CPUとキャッシュの間では32bit転送も64bit転送も一回で済んでいる、なんて言えません(とは言え、CPU・キャッシュ間の64bit転送を32bit転送2回に分けたりしないとは思うが)。
11
+
12
+ むしろ、8〜32bitの除算はCPU内部で同一ビット長の除算器を使うのだろうか?とも思いました。なぜならa_saitohさんが仰る通り「整数の割り算はビット長が長いほど手間がかかる」ものだから。しかし一方で、KSwordOfHasteさんが示唆されたように、CPUにとってキャッシュでさえも遅いかもしれず、8〜32bit除算ではCPU動作時間の違いがキャッシュアクセス時間の中に埋もれたのかもしれません。どうなのか、私にはわかりかねます。
13
+
14
+ 結論的には、ビット数が多いほど時間のかかる割り算で「得意なビット数」を考えるってどうよ、そもそも実験の方針が不適当では?という事で、私的にベストアンサーはa_saitohさんです。
15
+ 以上、お詫びを兼ねて訂正いたします。
16
+
17
+ ---
1
18
  > なぜ、8bitや16bitの方が32bitや64bitより早いのでしょうか??
2
19
 
3
20
  ここは「早い」ではなく「速い」と書くべき。違い、わかりますか?

3

追記3への回答を追加

2017/12/23 01:30

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -52,4 +52,15 @@
52
52
 
53
53
  ただ、仮にCPUとメモリの間のバスが32bitだとすると、64bitの転送に2回の動作が必要になるから、64bit命令が大きく不利になるのは明らかです。しかし32bitと64bitの実行時間がほぼ同じ結果だから、CPUとメモリ(実際はCPUとキャッシュ)の間は64bit転送も1回の動作で済んでいるはずです(この段落、追記しました)。
54
54
 
55
- 加えて、この狭い範囲のメモリしか使わないのだから、キャッシュの問題でもありません。メモリアクセスは、ほぼ全てがキャッシュアクセスで済んでいるはずです。念の為、追記:N回ループするコードも命令キャッシュにすっぽり入ってしまいます。
55
+ 加えて、この狭い範囲のメモリしか使わないのだから、キャッシュの問題でもありません。メモリアクセスは、ほぼ全てがキャッシュアクセスで済んでいるはずです。念の為、追記:N回ループするコードも命令キャッシュにすっぽり入ってしまいます。
56
+
57
+ 追記3へ
58
+ > CPUには得意なデータ型がある。変数のサイズがCPUのレジスタ長と一致していれば相性が良い?
59
+
60
+ 一般的にそうでしょう。余計なビットを切り落とす命令が不要、足りないビットを補う命令も不要、なのだから。ただ、絶対のルールかどうかは知らないよ。
61
+
62
+ > 機械語だけだとすると「Nbitの精度を保証して、かつ処理効率が最速になる型」を定義する必要はありませんよね??
63
+
64
+ 機械語と言っても実際はアセンブリ言語でプログラムする場合だと思うが、機械語(とオペランドサイズ等)を選択するのはプログラマの責務ですからね。
65
+ 何を元にして選択するかと言えば、一番重要なのはアーキテクチャの理解であることは論を待たないわけで、そこに、どの機械語が相応しいか、判断できるだけの情報を仕入れているか、ということになります。
66
+ コンパイラの作者はそうした情報に精通しているはずですが、実際は最初から100%良いコードを生成出きるとは限らなくて、コンパイラのバージョンアップで改良するわけです。

2

コードのコメント、誤りを修正

2017/12/16 05:52

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -26,7 +26,7 @@
26
26
  78b: 48 f7 7d d8 idivq -0x28(%rbp)
27
27
  78f: 48 89 45 b8 mov %rax,-0x48(%rbp)
28
28
 
29
- # long long ll3 = l1 / l2;
29
+ # long long ll3 = ll1 / ll2;
30
30
  7f3: 48 8b 45 d0 mov -0x30(%rbp),%rax
31
31
  7f7: 48 99 cqto
32
32
  7f9: 48 f7 7d c8 idivq -0x38(%rbp)

1

若干の追記

2017/12/16 04:25

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -6,27 +6,27 @@
6
6
  それぞれN回の割り算をfor文で繰り返す、その繰り返し方は全く同じだから、**違うのはループの中身**です。その中身を抽出すると、こうなります。
7
7
 
8
8
  ```
9
- # char
9
+ # char c3 = c1 / c2;
10
10
  6ac: 0f be 45 f7 movsbl -0x9(%rbp),%eax
11
11
  6b0: 0f be 4d f6 movsbl -0xa(%rbp),%ecx
12
12
  6b4: 99 cltd
13
13
  6b5: f7 f9 idiv %ecx
14
14
  6b7: 88 45 b5 mov %al,-0x4b(%rbp)
15
15
 
16
- # short
16
+ # short s3 = s1 / s2;
17
17
  716: 0f bf 45 ea movswl -0x16(%rbp),%eax
18
18
  71a: 0f bf 75 e8 movswl -0x18(%rbp),%esi
19
19
  71e: 99 cltd
20
20
  71f: f7 fe idiv %esi
21
21
  721: 66 89 45 b6 mov %ax,-0x4a(%rbp)
22
22
 
23
- # long
23
+ # long l3 = l1 / l2;
24
24
  785: 48 8b 45 e0 mov -0x20(%rbp),%rax
25
25
  789: 48 99 cqto
26
26
  78b: 48 f7 7d d8 idivq -0x28(%rbp)
27
27
  78f: 48 89 45 b8 mov %rax,-0x48(%rbp)
28
28
 
29
- # long long
29
+ # long long ll3 = l1 / l2;
30
30
  7f3: 48 8b 45 d0 mov -0x30(%rbp),%rax
31
31
  7f7: 48 99 cqto
32
32
  7f9: 48 f7 7d c8 idivq -0x38(%rbp)
@@ -43,10 +43,13 @@
43
43
  一般的には、**メモリを何回読むか、メモリに何回書くか**、その回数も実行時間に大きく効いてきます。個々の命令を見て、CPUとメモリの間の転送を整理してみると速度の違いが見えてくることがあります。ただ上記の機械語コードは、どれも2回読んで1回書き出しており、そこに大きな違いが感じられません。なので、各機械語のクロック数を調べる事ですね。
44
44
 
45
45
  一方、cateye さんのAMD機での実行時間は16, 32, 64bit が、ほぼ 0.33 秒で横並びだから、(8bit, 16bitのコードは示されたけど)32bit, 64bit でどんな命令か拝見したいですね。strike君の場合と違うはずです。
46
+ asmさんの結果は 64bit だけ余計に時間がかかっているから、64bitのところの機械語パターンが違うのではないかな。これもループの中身を比較してみると、何かわかるでしょう。もしかすると、同じ機械語を使うように修正できれば、strike君の手元でも結果が大きく違ってくるはず。
46
47
 
47
48
  > アライメントに関わる問題
48
49
 
49
50
  ではないと思います。
50
51
  スタックに配置された 15 個の変数は、具体的には、-0x4b(%rbp) から -0x8(%rbp) に割り当てられています。コンパイラは、全てアラインメントの問題が無い、最適な配置をしていると思いますが、どれか、アラインメントが悪そうな変数、ありますか?それとも、%rbp がアラインメントのズレたメモリを指してますか?
51
52
 
53
+ ただ、仮にCPUとメモリの間のバスが32bitだとすると、64bitの転送に2回の動作が必要になるから、64bit命令が大きく不利になるのは明らかです。しかし32bitと64bitの実行時間がほぼ同じ結果だから、CPUとメモリ(実際はCPUとキャッシュ)の間は64bit転送も1回の動作で済んでいるはずです(この段落、追記しました)。
54
+
52
- 加えて、この狭い範囲のメモリしか使わないのだから、キャッシュの問題でもありません。メモリアクセスは、ほぼ全てがキャッシュアクセスで済んでいるはずです。
55
+ 加えて、この狭い範囲のメモリしか使わないのだから、キャッシュの問題でもありません。メモリアクセスは、ほぼ全てがキャッシュアクセスで済んでいるはずです。念の為、追記:N回ループするコードも命令キャッシュにすっぽり入ってしまいます。