当目标位于另一个AppDomain中时,托管回调未受管理的速度要慢得多

时间:2017-04-01 04:37:11

标签: performance c++-cli interop clr

我使用委托从非托管代码调用托管代码。当我在默认的AppDomain中调用托管代码时,我每次调用的平均值为5.4ns。当我拨打第二个AppDomain时,我每次呼叫的测量值为194ns。 (默认VS2017 x86发布配置,未在调试器下运行)。

为什么在调用不是默认值的AppDomain时性能会低得多?由于我来自非托管端,不了解AppDomains,我希望直接进入目标域。但是,性能打击意味着委托调用默认域然后编组到真实目标。单步执行反汇编时,我确实看到了UM2MDoADCallBack。它显示在UMThunkStub.asm

中的WrongAppDomain:

如何防止这种不必要的封送并直接调用特定的AppDomain?

我用来测试的代码如下。

#pragma unmanaged
#include <wtypes.h>
#include <cstdint>
#include <cwchar>

typedef void (__stdcall *ManagedUpdatePtr)();

struct ProfileSample
{
    static uint64_t frequency;
    uint64_t startTick;
    wchar_t* name;
    int count;

    ProfileSample(wchar_t* name_, int count_)
    {
        name = name_;
        count = count_;

        LARGE_INTEGER win32_startTick;
        QueryPerformanceCounter(&win32_startTick);
        startTick = win32_startTick.QuadPart;
    }

    ~ProfileSample()
    {
        LARGE_INTEGER win32_endTick;
        QueryPerformanceCounter(&win32_endTick);
        uint64_t endTick = win32_endTick.QuadPart;

        uint64_t deltaTicks = endTick - startTick;
        double nanoseconds = (double) deltaTicks / (double) frequency * 1000000000.0 / count;

        wchar_t buffer[128];
        swprintf(buffer, _countof(buffer), L"%s - %.4f ns\n", name, nanoseconds);
        OutputDebugStringW(buffer);

        if (!IsDebuggerPresent())
            MessageBoxW(nullptr, buffer, nullptr, 0);
    }
};

uint64_t ProfileSample::frequency = 0;

int CALLBACK
WinMain(HINSTANCE, HINSTANCE, PSTR, INT)
{
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    ProfileSample::frequency = frequency.QuadPart;

    ManagedUpdatePtr GetManagedUpdatePtr();
    auto managedUpdate = GetManagedUpdatePtr();

    //Warm stuff up
    for ( size_t i = 0; i < 100; i++ )
        managedUpdate();

    const int num = 10000000;
    {
        ProfileSample p(L"ManagedUpdate", num);

        for ( size_t i = 0; i < num; i++ )
            managedUpdate();
    }

    return 0;
}

#pragma managed
using namespace System;
using namespace System::Diagnostics;
using namespace System::Runtime::InteropServices;

ref struct ManagedObject : MarshalByRefObject
{
    ManagedUpdatePtr
    GetManagedUpdatePtr()
    {
        auto delegate = gcnew Action(this, &ManagedObject::ManagedUpdate);

        IntPtr fPtr = Marshal::GetFunctionPointerForDelegate(delegate);
        return (ManagedUpdatePtr) fPtr.ToPointer();
    }

    void ManagedUpdate()
    {
        //Debug::WriteLine("\n\nManagedUpdate ({0})", (Object^) AppDomain::CurrentDomain->FriendlyName);
    }
};


ManagedUpdatePtr
GetManagedUpdatePtr()
{
    auto pluginDomain = AppDomain::CreateDomain("Plugin Domain");
    auto managedObject = (ManagedObject^) pluginDomain->CreateInstanceAndUnwrap("ManagedHelper", "ManagedObject");

    return managedObject->GetManagedUpdatePtr();
}

0 个答案:

没有答案