[英]FileNotFoundException when calling remote C# dll from C++/CLR
[英]How does the CLR avoid thunking when calling c++ functions?
MSDN聲明 :
無論使用何種互操作技術,每次托管函數調用非托管函數時都需要特殊的轉換序列(稱為thunks),反之亦然。 這些thunk是由Visual C ++編譯器自動插入的,但重要的是要記住,累積起來,這些轉換在性能方面可能很昂貴。
然而,CLR肯定會一直調用C ++和Win32函數。 為了處理文件/網絡/窗口以及幾乎任何其他內容,必須調用非托管代碼。 它是如何擺脫分塊懲罰的?
這是一個用C ++ / CLI編寫的實驗,可能有助於描述我的問題:
#define REPS 10000000
#pragma unmanaged
void go1() {
for (int i = 0; i < REPS; i++)
pow(i, 3);
}
#pragma managed
void go2() {
for (int i = 0; i < REPS; i++)
pow(i, 3);
}
void go3() {
for (int i = 0; i < REPS; i++)
Math::Pow(i, 3);
}
public ref class C1 {
public:
static void Go() {
auto sw = Stopwatch::StartNew();
go1();
Console::WriteLine(sw->ElapsedMilliseconds);
sw->Restart();
go2();
Console::WriteLine(sw->ElapsedMilliseconds);
sw->Restart();
go3();
Console::WriteLine(sw->ElapsedMilliseconds);
}
};
//Go is called from a C# app
結果是(一致地):
405 (go1 - pure C++)
818 (go2 - managed code calling C++)
289 (go3 - pure managed)
為什么go3比go1更快有點神秘,但這不是我的問題。 我的問題是,我們從go1&go2看到,thunking懲罰增加了400ms。 go3如何擺脫這種懲罰, 因為它調用C ++來進行實際計算?
即使這個實驗由於某種原因無效,我的問題仍然存在 - 每次調用C ++ / Win32時,CLR是否真的有一個thunking懲罰?
基准測試是一種黑色藝術,你在這里得到了一些誤導性的結果。 運行Release版本非常重要,如果你這樣做,那么你現在會注意到go1()不再需要時間了。 本機代碼優化器具有它的特殊知識,如果你不使用它的結果,那么它完全消除它。
您必須更改代碼才能獲得可靠的結果。 首先在Go()測試體周圍放置一個循環,重復至少20次。 這消除了jitting和緩存開銷,並有助於查看大的標准偏差。 敲掉REPS 0,這樣你就不用等太久了。 贊成工具>選項>調試>常規,“抑制JIT優化”未選中。 更改代碼,我建議:
__declspec(noinline)
double go1() {
double sum = 0;
for (int i = 0; i < REPS; i++)
sum += pow(i, 3);
return sum;
}
注意sum變量如何強制優化器保持調用,使用__declspec可以防止刪除整個函數並避免污染Go()體。 對go2和go3執行相同操作,使用[MethodImpl(MethodImplOptions :: NoInlining)]。
我在筆記本電腦上看到的結果:x64:75,84,84,x86:73,89,89 + 5 / -3毫秒。
工作中有三種不同的機制:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.