C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

同じコードで実行時間が異なる理由

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■97921 / inTopicNo.1)  同じコードで実行時間が異なる理由
  
□投稿者/ 山善 (1回)-(2021/08/09(Mon) 12:50:44)

分類:[.NET 全般] 

以下のコードを実行すると
138 ms
53 ms
326 ms

二つ目は一つ目と同じ配列を使っているのに3倍近く計算時間が速くなってしまいます。

三つめは、単に違う配列を使っただけで全く同じコードなのに一つ目よりも3倍近く遅くなってしまいます。

デバッグモードではなく、リリースモードを使っていますし、
何度か試してみたのですが
何度やっても同じような結果になってしまいます。

これってなぜなのでしょうか?


        Dim sw As New Stopwatch

        Dim Hai(100000000) As Integer


        sw.Restart()

        For i = 1 To 100000000

            Hai(i) = 1

        Next
        '138 ms
        MsgBox(sw.ElapsedMilliseconds)



        sw.Restart()

        For i = 1 To 100000000

            Hai(i) = 2

        Next
        '53 ms
        MsgBox(sw.ElapsedMilliseconds)



        Dim Hai2(100000000) As Integer

        sw.Restart()

        For i = 1 To 100000000

            Hai2(i) = 1

        Next
        '326 ms
        MsgBox(sw.ElapsedMilliseconds)


引用返信 編集キー/
■97923 / inTopicNo.2)  Re[1]: 同じコードで実行時間が異なる理由
□投稿者/ 古谷 (4回)-(2021/08/09(Mon) 21:12:17)
CPUのキャッシュとか、GCとか、JITコンパイルとかじゃないかな、知らないけど
引用返信 編集キー/
■97924 / inTopicNo.3)  Re[2]: 同じコードで実行時間が異なる理由
□投稿者/ しま (1回)-(2021/08/09(Mon) 22:32:48)
No97921 (山善 さん) に返信
> 

仮想記憶だから Dim Hai(100000000) as Integer なんていう巨大な領域が一度に確保できるわけではないからではないかな?

この配列を宣言したところで、領域全体が実記憶として割当たるわけでいはない。

For i = 1 to 100000000
    Hai(i)=1
Next

このループの中で、実記憶として初めてアクセスする(ブロックとして)度に実記憶が割当たるのです。

そして、2度目のループ

For i = 1 to 100000000
    Hai(i) = 2
Next

では、実記憶の確保(=割当)は起きない(ページイン、ページアウトは起きるだろうけれども)ので、その分時間が掛からない。

で説明できると思う。

又、三度目のループの実行時間については、最初のループより実行時間が掛かる点については実行環境が関わってるので
プロセッサーのキャッシュの大きさや、主記憶の大きさ、32bit OS なのか 64bit OS なのかなどが関係すると思われるので
これだとはっきりとは言えませんね。ほぼ 40MB の配列の大きさなので、プロセッサーのキャッシュに納まりきれそうにないので
プロセッサーのキャッシュと主記憶との入れ替えは起こっていそうだとは想像できますが...

引用返信 編集キー/
■97925 / inTopicNo.4)  Re[3]: 同じコードで実行時間が異なる理由
□投稿者/ 山善 (2回)-(2021/08/09(Mon) 22:49:16)
しまさん

ありがとうございます。

2つ目のループに関しては納得しました。
このような仕組みになっていたのですね。



3つ目のループに関してですが
x86モードでビルドした場合には、違いが見られたのですが
x64モードにすると違いは見られなくなりました。


しかし、配列のサイズはたったの40MBなので、
32bitの壁である2GBよりかは十分に小さいので関係ないと思います。

主記憶は32GBを使っており、
CPUには
https://ark.intel.com/content/www/jp/ja/ark/products/94456/intel-core-i7-6950x-processor-extreme-edition-25m-cache-up-to-3-50-ghz.html

これを使っています。

キャッシュ25MBと書かれてあるので、
40MBに近いですが、わずかに小さいので、
一つ目の配列を宣言した時点でキャッシュは足りなくなって
主記憶を使うため、
二つ目の配列と速度に差異は出なくなると思います。

一体、何が原因でしょうか?


引用返信 編集キー/
■97926 / inTopicNo.5)  Re[4]: 同じコードで実行時間が異なる理由
□投稿者/ しま (2回)-(2021/08/10(Tue) 01:10:22)
No97925 (山善 さん) に返信
> しまさん
>
> ありがとうございます。
>
> 2つ目のループに関しては納得しました。
> このような仕組みになっていたのですね。
>
>
>
> 3つ目のループに関してですが
> x86モードでビルドした場合には、違いが見られたのですが
> x64モードにすると違いは見られなくなりました。
>
>
> しかし、配列のサイズはたったの40MBなので、
> 32bitの壁である2GBよりかは十分に小さいので関係ないと思います。
>
> 主記憶は32GBを使っており、
> CPUには
> https://ark.intel.com/content/www/jp/ja/ark/products/94456/intel-core-i7-6950x-processor-extreme-edition-25m-cache-up-to-3-50-ghz.html
>
> これを使っています。
>
> キャッシュ25MBと書かれてあるので、
> 40MBに近いですが、わずかに小さいので、
> 一つ目の配列を宣言した時点でキャッシュは足りなくなって
> 主記憶を使うため、
> 二つ目の配列と速度に差異は出なくなると思います。
>
> 一体、何が原因でしょうか?
>

少し調べてみました(キャッシュはあなたが考えいるように単純ではありません)。
あまり古くないプロセッサー内部のキャッシュは3階層になっていて、 i7-6950 では次のようになっている様です

L3: 25 MB
L2: 256KB
L1: 32KB

しかも、キャッシュメモリーの内すべてがデーター領域に割当たっているわけではないので、 25MB のキャッシュ中にどれだけ
Hai() や Hai2() やが居るかはある瞬間、瞬間で変わってしまうでしょう。

常に、特定のアプリケーションだけが、キャッシュ中に存在するわけではないことを忘れてはいけないと思います。
OS や サービスやアプリケーションなどがキャッシュに同居しているのですから。

引用返信 編集キー/
■97944 / inTopicNo.6)  Re[5]: 同じコードで実行時間が異なる理由
□投稿者/ 山善 (3回)-(2021/08/10(Tue) 21:02:23)
No97926 (しま さん) に返信

そうなのですね。
どうもありがとうございます。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ