2012-05-23 19 views
2

假設我需要實現一個out-proc COM服務器,並且所有的COM接口都是自動化兼容的。我可以創建並註冊一個代理/存根組合或者創建並註冊一個類型庫,並依賴自動化編組器。代理/存根和typelib封送處理性能如何比較?

我很清楚這兩種方法的所有維護方面。這個問題只關於運行時性能。

我無法找到任何硬盤數據 - 僅索賠

  1. 「自動化編組是通用的,所以它是比較慢」,我不會相信馬上因爲只差幾個自動化兼容的類型,所以它們之間的切換並不困難

  2. 「自動編組器將不得不加載類型庫」這是公平點,但這將只需要做一次,如果我有十萬個COM後來我不在乎那些一次性開銷

是否有任何測量數據 - 代理/存根編組或者typelib編組 - 在長期運行中速度更快?

回答

1

一旦代理被創建,PSOAInterface的性能應該是相同的,一個/ Oicf代理/存根庫,根據唐盒在基本的COM(第228頁),並his Microsoft Systems Journal article (Jan 1999)

但是從Windows 8.1起,PSOAInterface代理的創建可能非常不理想。 Don Box在上面的文章中聲明瞭combase!CreateProxyFromTypeInfo和類型庫封送拆分器執行緩存。但是,在我的測試中,每次釋放所有接口後,都會從文件中重新加載類型庫。這是UIAutomation庫的一個重要問題,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