P/Invokeのテスト

以前も似たような実験をやった気がしますが、パフォーマンス調査もかねて。
まず、C#から呼び出すC言語で書いたDLL。

#include <stdio.h>

__declspec(dllexport) void PrintStr(const char* str)
{
    // printf("%s\n", str);
}

char*を受け取るだけの関数です。次にこれを呼び出すC#のコード。

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

public class App {
    [DllImport("mydll")]
    public static extern void PrintStr(string msg);

    [DllImport("mydll", EntryPoint="PrintStr")]
    public static extern void PrintBytes(byte msg);

    [DllImport("mydll", EntryPoint="PrintStr")]
    public static extern void PrintPtr(IntPtr msg);


    const int LOOP = 10000000;
    const string msg = "あいうえおかきくけこさしすせそたちつてと";

    unsafe public static void Main() {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < LOOP; ++i)
            PrintStr(msg);
        sw.Stop();
        Console.WriteLine (sw.ElapsedMilliseconds);

        byte bytes = Encoding.GetEncoding(932).GetBytes(msg);
        sw.Reset();
        sw.Start();
        for (int i = 0; i < LOOP; ++i)
            PrintBytes(bytes);
        sw.Stop();
        Console.WriteLine (sw.ElapsedMilliseconds);

        fixed (byte* p = &bytes[0]) {
            IntPtr q = (IntPtr)p;
            sw.Reset();
            sw.Start();
            for (int i = 0; i < LOOP; ++i) 
                PrintPtr(q);
            sw.Stop();
            Console.WriteLine (sw.ElapsedMilliseconds);
        }
    }
}

/* 結果
.NET 2.0 (11MB)
4086
787
745

Mono 1.1.14 (600MB)
9312
281
156
 */

.NET2.0とMono1.1.14の両方で試しています。

.NET2.0の結果ですが、stringが遅いのは、まぁ仕方がありません。毎回エンコーディングしているし。しかし、byteとIntPtrに差がないのが予想外でした。

Mono1.1.14の場合、byteとIntPtrに差が出ています。こっちの方が私の予想に近い形ですね。.NET2.0よりかなり速いのが気になりますが、CAS周りの所為かしら。一方でstringがかなり遅いです。原因は、私のマシンがメモリ不足でスワップをおこした所為なんですが(25秒くらい掛かった時もあった)、Monoでstringの例だとメモリを600MBくらい食うんですよね。なんでだろう・・・