プロファイル(new)その2
C#はMSIL(CIL)という中間言語に変換してから各プラットフォーム用に実行ファイルを作成します。
C#で作成したexeファイルを逆アセンブルかけて、MSILを見ることができるので、設定してみましょう。
まずは、自分のWindowsの中に「ildasm.exe」を探します、そしてVS.NETの[ツール]の[外部ツール]を選択し以下のように設定します。
・タイトルに今回は「ILDASM」を設定
・コマンドには「ildasm.exe」をフルパスで設定してください。
・引数には「$(TargetPath)」を設定してください。
そして、逆アセンブルするには[ツール]に[ILDASM]が選択できるようになります、それを踏まえ、前回作成したプログラムを比較したいと思います。
■Type2
private void timeTest() { int[] iData = new int[100]; for (int i = 0; i < 1000000; i++) { for (int j = 0; j < 100; j++) iData[j] = j; } }
.method private hidebysig instance void timeTest() cil managed { // コード サイズ 42 (0x2a) .maxstack 3 .locals init ([0] int32[] iData, [1] int32 i, [2] int32 j) IL_0000: ldc.i4.s 100 IL_0002: newarr [mscorlib]System.Int32 IL_0007: stloc.0 IL_0008: ldc.i4.0 IL_0009: stloc.1 IL_000a: br.s IL_0021 IL_000c: ldc.i4.0 IL_000d: stloc.2 IL_000e: br.s IL_0018 IL_0010: ldloc.0 IL_0011: ldloc.2 IL_0012: ldloc.2 IL_0013: stelem.i4 IL_0014: ldloc.2 IL_0015: ldc.i4.1 IL_0016: add IL_0017: stloc.2 IL_0018: ldloc.2 IL_0019: ldc.i4.s 100 IL_001b: blt.s IL_0010 IL_001d: ldloc.1 IL_001e: ldc.i4.1 IL_001f: add IL_0020: stloc.1 IL_0021: ldloc.1 IL_0022: ldc.i4 0xf4240 IL_0027: blt.s IL_000c IL_0029: ret } // end of method Game1::timeTest
■Type3
private int[] iData = new int[100]; private void timeTest() { for (int i = 0; i < 1000000; i++) { for (int j = 0; j < 100; j++) iData[j] = j; } }
.method private hidebysig instance void timeTest() cil managed { // コード サイズ 39 (0x27) .maxstack 3 .locals init ([0] int32 i, [1] int32 j) IL_0000: ldc.i4.0 IL_0001: stloc.0 IL_0002: br.s IL_001e IL_0004: ldc.i4.0 IL_0005: stloc.1 IL_0006: br.s IL_0015 IL_0008: ldarg.0 IL_0009: ldfld int32[] Profiler.Game1::iData IL_000e: ldloc.1 IL_000f: ldloc.1 IL_0010: stelem.i4 IL_0011: ldloc.1 IL_0012: ldc.i4.1 IL_0013: add IL_0014: stloc.1 IL_0015: ldloc.1 IL_0016: ldc.i4.s 100 IL_0018: blt.s IL_0008 IL_001a: ldloc.0 IL_001b: ldc.i4.1 IL_001c: add IL_001d: stloc.0 IL_001e: ldloc.0 IL_001f: ldc.i4 0xf4240 IL_0024: blt.s IL_0004 IL_0026: ret } // end of method Game1::timeTest
■Type4
private void timeTest() { int[] pData = iData; for (int i = 0; i < 1000000; i++) { for (int j = 0; j < 100; j++) pData[j] = j; } }
.method private hidebysig instance void timeTest() cil managed { // コード サイズ 41 (0x29) .maxstack 3 .locals init ([0] int32[] pData, [1] int32 i, [2] int32 j) IL_0000: ldarg.0 IL_0001: ldfld int32[] Profiler.Game1::iData IL_0006: stloc.0 IL_0007: ldc.i4.0 IL_0008: stloc.1 IL_0009: br.s IL_0020 IL_000b: ldc.i4.0 IL_000c: stloc.2 IL_000d: br.s IL_0017 IL_000f: ldloc.0 IL_0010: ldloc.2 IL_0011: ldloc.2 IL_0012: stelem.i4 IL_0013: ldloc.2 IL_0014: ldc.i4.1 IL_0015: add IL_0016: stloc.2 IL_0017: ldloc.2 IL_0018: ldc.i4.s 100 IL_001a: blt.s IL_000f IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: add IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldc.i4 0xf4240 IL_0026: blt.s IL_000b IL_0028: ret } // end of method Game1::timeTest
アセンブラでプログラムを書きましょうという話ではありません、ただ、どのようなコードを書けばどのような結果になるのかは意識したほうが後々、楽ができるので、いろいろとテストしてみると良いです。
for (int j = 0; j < 100; j++) iData[j] = j;
だけ見てみると、ローカル変数の場合
IL_000f: ldloc.0 IL_0010: ldloc.2 IL_0011: ldloc.2 IL_0012: stelem.i4 IL_0013: ldloc.2 IL_0014: ldc.i4.1 IL_0015: add IL_0016: stloc.2 IL_0017: ldloc.2 IL_0018: ldc.i4.s 100
グローバル変数の場合
IL_000e: ldloc.1 IL_000f: ldloc.1 IL_0010: stelem.i4 IL_0011: ldloc.1 IL_0012: ldc.i4.1 IL_0013: add IL_0014: stloc.1 IL_0015: ldloc.1 IL_0016: ldc.i4.s 100
なので、ちょっとはやくなるのかもしれませんね