JIT GPUコンパイラを作成したいと思います。あなたはF#関数を与え、それをJITコンパイルします。 JITコンパイルの鍵は、コンパイル結果をキャッシュすることです。キャッシングキーとしてMethodInfo
を使用しようとしましたが、動作しません。 F#コンパイラは、元の関数を参照するのではなく、関数のコピーを作成するようです。この動作を抑制する方法はありますか?ILコードで関数のコピーを作成するF#コンパイラを抑制できますか?
ここではテストコードですが、理想的には2回だけコンパイルする必要がありますが、それは4回でした。ここで
let compileGpuCode (m:MethodInfo) =
printfn "JIT compiling..."
printfn "Type : %A" m.ReflectedType
printfn "Method: %A" m
printfn ""
"fake gpu code"
let gpuCodeCache = ConcurrentDictionary<MethodInfo, string>()
let launchGpu (func:int -> int -> int) =
let m = func.GetType().GetMethod("Invoke", [| typeof<int>; typeof<int> |])
let gpuCode = gpuCodeCache.GetOrAdd(m, compileGpuCode)
// launch gpuCode
()
let myGpuCode (a:int) (b:int) = a + 2 * b
[<Test>]
let testFSFuncReflection() =
launchGpu (+)
launchGpu (+)
launchGpu myGpuCode
launchGpu myGpuCode
が出力されます。
JIT compiling...
Type : [email protected]
Method: Int32 Invoke(Int32, Int32)
JIT compiling...
Type : [email protected]
Method: Int32 Invoke(Int32, Int32)
JIT compiling...
Type : [email protected]
Method: Int32 Invoke(Int32, Int32)
JIT compiling...
Type : [email protected]
Method: Int32 Invoke(Int32, Int32)
あなたが 'myGpuCode'を渡すたびに、新しい委譲を作成します。それらのそれぞれは、基礎となる関数を呼び出す別の関数(クロージャ)です。私が知る限り、入力関数のアイデンティティを保持する簡単な方法はありません。 – Luaan
@Luaanカレー関数を作成すると、新しいデリゲート(クロージャ)を作成するのが妥当であると思います。しかし、関数を参照しているだけの場合は、新しいコピーを作成するのではなく、参照するための最適化が必要です。 C#では、デリゲート型は元のメソッドを参照しますが、もちろんC#のラムダ関数も、クロージャの新しいメソッドを作成します。 –
C#では、基になるメソッドをラップするデリゲートを取得します。しかしそれは保証ではなく、あなたが閉鎖しているときでもアイデンティティは保持されません。あなたがC#で類似のコードを使用した場合、 'launchGpu(()=> myGpuCode(...))'を同じクラスに入れておくと動作しますが、2つのクラスを使用するとすぐに中断しますラップされた関数を呼び出す2つの別個のメソッドを再度取得します)。私はあなたが未定義の領域に深くいるのではないかと心配しています。解決策が見つかると、F#コンパイラまたは.NETランタイムの変更により将来的には破損する可能性があります。 – Luaan