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くらい食うんですよね。なんでだろう・・・