proxy / stub和typelib封送性能如何比较?

时间:2012-05-23 14:21:44

标签: performance com interop marshalling

假设我需要实现一个out-proc COM服务器,并且所有COM接口都是自动化兼容的。我可以创建和注册代理/存根组合,也可以创建和注册类型库,并依赖Automation marshaller。

我很清楚这两种方法的所有维护方面。这个问题仅与运行时性能有关。

我找不到任何硬数据 - 只有声明,如

  1. “自动化编组器是通用的,因此速度较慢”,我不会马上相信,因为只有几种与自动化兼容的类型,因此它们之间的切换并不那么难

  2. “自动化编组必须加载类型库”这是公平的,但这只需要进行一次,如果我之后有数十万次COM调用,那我就不在乎那个 - 开销时间

  3. 从长远来看,是否有任何测量数据 - 代理/存根封送或类型库封送 - 更快?

1 个答案:

答案 0 :(得分:1)

根据 Essential Com 中的Don Box(p.228)和{{3>创建代理后,PSOAInterface的性能应与/ Oicf代理/存根库的性能相同。 }}

但是从Windows 8.1开始,PSOAInterface代理的创建可能非常不理想。 Don Box在上面的文章中声称,combase!CreateProxyFromTypeInfo和类型库封送程序执行缓存。但是,在我的测试中,每次释放所有接口后,都会从文件重新加载类型库。这是UIAutomation库的一个重要问题,它广泛使用IGlobalInterfaceTable,导致一系列额外的系统调用。

这是我的测试。一个公寓实例化一个coclass,然后另一个公寓将其解组为代理10000次。使用PSOAInterface时大约需要5秒。如果我改为创建并注册一个MIDL代理/存根,它只需要大约100ms。

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <comdef.h>

// RemoteProxyFactory32 from oleacc.dll {53362c64-a296-4f2d-a2f8-fd984d08340b}
static IID CLSID_RemoteProxyFactory32 = GUID{ 0x53362c64, 0xa296, 0x4f2d, { 0xa2, 0xf8, 0xfd, 0x98, 0x4d, 0x08, 0x34, 0x0b } };
// IRemoteProxyFactory from oleacc.dll {8628f27d-64a2-4ed6-906b-e6155314c16a}
static IID IID_IRemoteProxyFactory = GUID{ 0x8628f27d, 0x64a2, 0x4ed6, { 0x90, 0x6b, 0xe6, 0x15, 0x53, 0x14, 0xc1, 0x6a } };

struct register_interface_thread {
    HANDLE hInterfaceRegistered;
    DWORD dwCookie;
    HANDLE hShouldClose;
};
DWORD WINAPI RegisterInterfaceThread(_In_  LPVOID lpParameter) {
    struct register_interface_thread& state = *(struct register_interface_thread*)(lpParameter);
    HRESULT hr;
    if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
        fprintf(stderr, "Error CoInitializeEx: 0x%08x\n", hr);
    }
    else {
        IUnknown *pv;
        if (FAILED(hr = CoCreateInstance(CLSID_RemoteProxyFactory32, NULL, CLSCTX_LOCAL_SERVER, IID_IRemoteProxyFactory, (LPVOID*)&pv))) {
            fprintf(stderr, "CocCreateInstance(RemoteProxyFactory32 of oleacc.dll) failed with hresult 0x%x\n", hr);
        }
        else {
            IGlobalInterfaceTable *pIGlobalInterfaceTable;
            if (FAILED(hr = CoCreateInstance
                (
                CLSID_StdGlobalInterfaceTable,
                NULL,
                CLSCTX_INPROC_SERVER,
                IID_IGlobalInterfaceTable,
                (void **)&pIGlobalInterfaceTable
                ))) {
                fprintf(stderr, "CocCreateInstance(StdGlobalInterfaceTable) failed with hresult 0x%x\n", hr);
            }
            else {
                DWORD dwCookie;
                if (FAILED(hr = pIGlobalInterfaceTable->RegisterInterfaceInGlobal(pv, IID_IRemoteProxyFactory, &dwCookie))) {
                    fprintf(stderr, "RegisterInterfaceInGlobal failed with hresult 0x%x\n", hr);
                }
                else {
                    fprintf(stdout, "Successfully registered interface; cookie=0x%x\n", dwCookie);
                    state.dwCookie = dwCookie;
                    if (!SetEvent(state.hInterfaceRegistered)) {
                        DWORD err = GetLastError();
                        fprintf(stderr, "Error SetEvent(hInterfaceRegistered): 0x%x\n", err);
                    }
                    else {
                        DWORD waitResult;
                        if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(state.hShouldClose, INFINITE))) {
                            DWORD err = GetLastError();
                            fprintf(stderr, "Error WaitForSingleObject: returned 0x%x; error=0x%08x\n", waitResult, err);
                            hr = err;
                        }
                        else {
                            fprintf(stdout, "Successfully joined thread; dwCookie=0x%x\n", state.dwCookie);
                        }
                    }
                }
                pIGlobalInterfaceTable->Release();
            }
            if (pv != NULL)
                pv->Release();
        }
        CoUninitialize();
        fprintf(stdout, "Thread going away\n");
    }
    return 0;
}

int main(int argc, char* argv[]) {
    HRESULT hr;
    if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
        fprintf(stderr, "Error CoInitializeEx: 0x%08x\n", hr);
    }
    else {
        struct register_interface_thread state;
        state.dwCookie = 0;
        state.hInterfaceRegistered = CreateEventEx(NULL, TEXT("hInterfaceRegistered"), CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
        state.hShouldClose = CreateEventEx(NULL, TEXT("hShouldClose"), CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);

        HANDLE hThread = CreateThread(NULL, 0, RegisterInterfaceThread, &state, 0, NULL);
        if (hThread == NULL) {
            DWORD err = GetLastError();
            fprintf(stderr, "Error CreateThread: 0x%08x\n", err);
            hr = err;
        }
        else {
            DWORD waitResult;
            if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(state.hInterfaceRegistered, INFINITE))) {
                DWORD err = GetLastError();
                fprintf(stderr, "Error WaitForSingleObject: returned 0x%x; error=0x%08x\n", waitResult, err);
                hr = err;
            }
            else {
                fprintf(stdout, "Successfully waited for hInterfaceRegistered; dwCookie=0x%x\n", state.dwCookie);
                IGlobalInterfaceTable *pIGlobalInterfaceTable;
                if (FAILED(hr = CoCreateInstance
                    (
                    CLSID_StdGlobalInterfaceTable,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_IGlobalInterfaceTable,
                    (void **)&pIGlobalInterfaceTable
                    ))) {
                    fprintf(stderr, "CoCreateInstance(StdGlobalInterfaceTable) failed with hresult 0x%x\n", hr);
                }
                else {
                    IUnknown *pv = NULL;
                    DWORD start_time = GetTickCount();
                    DWORD i;
                    for (i = 0; i != 10000; i++) {
                        if (FAILED(hr = pIGlobalInterfaceTable->GetInterfaceFromGlobal(state.dwCookie, IID_IRemoteProxyFactory, (LPVOID*)&pv))) {
                            fprintf(stderr, "GetInterfaceFromGlobal failed with hresult 0x%x\n", hr);
                            break;
                        }
                        else {
                            pv->Release();
                        }
                    }
                    DWORD end_time = GetTickCount();
                    DWORD difference = end_time - start_time;
                    fprintf(stdout, "%u iterations completed in %ums\n", i, difference);
                    pIGlobalInterfaceTable->Release();
                }
                if (!SetEvent(state.hShouldClose)) {
                    DWORD err = GetLastError();
                    fprintf(stderr, "SetEvent(hShouldClose) failed; err=0x%x\n", err);
                    hr = err;
                }
                else {
                    if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(hThread, INFINITE))) {
                        DWORD err = GetLastError();
                        fprintf(stderr, "Error WaitForSingleObject(hThread): returned 0x%x; error=0x%08x\n", waitResult, err);
                        hr = err;
                    }
                    else {
                        printf("successfully joined thread.\n");
                    }
                }
            }
        }
    }
    return hr;
}

在windbg中运行它确认它重新加载类型库10000次。

bp KERNELBASE!CreateFileW "r $t0 = @$t0 + 1; g"
bp OLEAUT32!LoadTypeLibEx "r $t1 = @$t1 + 1; g"
g
r $t0, $t1
$t0=000000000000c35c $t1=0000000000002712