|
|
/*++
Copyright (C) Microsoft Corporation, 1994 - 1999
Module Name:
Client.c
Abstract:
Client side of basic RPC performance test.
Author:
Mario Goertzel (mariogo) 31-Mar-1994
Revision History:
--*/
#include <rpcperf.h>
#include <rpcrt.h>
#ifdef MAC
extern void _cdecl PrintToConsole(const char *lpszFormat, ...) ; extern unsigned long ulSecurityPackage ; #else
#define PrintToConsole printf
unsigned long ulSecurityPackage = RPC_C_AUTHN_WINNT ; #endif
// Usage
const char *USAGE = "-n <threads> -a <authnlevel> -s <server> -t <protseq> -w <wait_method>\n" "Server controls iterations, test cases, and compiles the results.\n" "AuthnLevel: none, connect, call, pkt, integrity, privacy.\n" "Default threads=1, authnlevel=none\n";
#define CHECK_RET(status, string) if (status)\
{ PrintToConsole("%s failed -- %lu (0x%08X)\n", string,\ (unsigned long)status, (unsigned long)status);\ return (status); \ }
#ifdef WIN98
RPC_DISPATCH_TABLE DummyDispatchTable = { 1, NULL };
RPC_SERVER_INTERFACE DummyInterfaceInformation = { sizeof(RPC_SERVER_INTERFACE), {{1,2,2,{3,3,3,3,3,3,3,3}}, {1,1}}, {{1,2,2,{3,3,3,3,3,3,3,3}}, {0,0}}, &DummyDispatchTable, 0, NULL, NULL, NULL, 0 }; #endif
RPC_STATUS DoRpcBindingSetAuthInfo(handle_t Binding) { if (AuthnLevel != RPC_C_AUTHN_LEVEL_NONE) return RpcBindingSetAuthInfo(Binding, NULL, AuthnLevel, ulSecurityPackage, NULL, RPC_C_AUTHZ_NONE); else return(RPC_S_OK); }
//
// Test wrappers
//
unsigned long DoNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) NullCall(*b);
return (FinishTiming()); }
unsigned long DoNICall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) NICall(*b);
return (FinishTiming()); }
unsigned long DoWrite1K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Write1K(*b,p);
return (FinishTiming()); }
unsigned long DoRead1K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Read1K(*b,p);
return (FinishTiming()); }
unsigned long DoWrite4K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Write4K(*b,p);
return (FinishTiming()); }
unsigned long DoRead4K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Read4K(*b,p);
return (FinishTiming()); }
unsigned long DoWrite32K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Write32K(*b,p);
return (FinishTiming()); }
unsigned long DoRead32K(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { StartTime();
while(i--) Read32K(*b,p);
return (FinishTiming()); }
unsigned long DoContextNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { unsigned long Time; PERF_CONTEXT pContext = OpenContext(*b);
StartTime();
while(i--) ContextNullCall(pContext);
Time = FinishTiming();
CloseContext(&pContext);
return (Time); }
unsigned long DoFixedBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { unsigned long status; unsigned long Time; char *stringBinding; char *ep = GetFixedEp(*b); handle_t binding;
RpcBindingFree(b);
RpcStringBindingCompose(0, Protseq, NetworkAddr, ep, 0, &stringBinding);
MIDL_user_free(ep);
StartTime(); while(i--) { RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding); CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding); } Time = FinishTiming();
//
// Restore binding for the rest of the test.
//
RpcBindingFromStringBinding(stringBinding, b); NullCall(*b); NullCall(*b); RpcStringFree(&stringBinding);
return (Time); }
unsigned long DoReBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { unsigned long status; unsigned long Time; char *stringBinding; char *ep = GetFixedEp(*b); handle_t binding;
RpcStringBindingCompose(0, Protseq, NetworkAddr, ep, 0, &stringBinding);
MIDL_user_free(ep);
StartTime(); while(i--) { RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding); CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding); } Time = FinishTiming();
RpcStringFree(&stringBinding);
return (Time); }
unsigned long DoDynamicBinding(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { unsigned long status; unsigned long Time; char *stringBinding; handle_t binding;
RpcBindingFree(b);
RpcStringBindingCompose(0, Protseq, NetworkAddr, 0, 0, &stringBinding);
StartTime(); while(i--) { RpcBindingFromStringBinding(stringBinding, &binding);
status = DoRpcBindingSetAuthInfo(binding); CHECK_RET(status, "RpcBindingSetAuthInfo");
NullCall(binding);
RpcBindingFree(&binding); } Time = FinishTiming();
//
// Restore binding for test to use.
//
RpcBindingFromStringBinding(stringBinding, b); NullCall(*b); NullCall(*b); RpcStringFree(&stringBinding);
return (Time); }
void AsyncProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent) { // no-op
}
void AsyncCallbackProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent) { // wake up our thread
// in hThread we actually keep an event
HANDLE hEvent = pAsync->u.APC.hThread;
SetEvent(hEvent); }
void NotifyProc(IN PRPC_ASYNC_STATE pAsync, IN void *context, IN RPC_ASYNC_EVENT asyncEvent) { // no-op
}
unsigned long DoAsyncNullCallWithEvent(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { HANDLE hEvent = pAsync->u.hEvent; RPC_STATUS RpcStatus;
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
pAsync->NotificationType = RpcNotificationTypeEvent; pAsync->u.hEvent = hEvent;
AsyncNullCall(pAsync, *b); WaitForSingleObject(hEvent, INFINITE); RpcAsyncCompleteCall(pAsync, NULL); }
return (FinishTiming()); }
unsigned long DoAsyncNullCallWithApc(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { RPC_STATUS RpcStatus;
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
pAsync->NotificationType = RpcNotificationTypeApc; pAsync->u.APC.NotificationRoutine = AsyncProc; pAsync->u.APC.hThread = 0;
AsyncNullCall(pAsync, *b); SleepEx(INFINITE, TRUE); RpcAsyncCompleteCall(pAsync, NULL); }
return (FinishTiming()); }
unsigned long DoAsyncNullCallWithCallback(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { RPC_STATUS RpcStatus; HANDLE hEvent; unsigned long nTiming;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!hEvent) { printf("CreateEvent failed: %ld\n", GetLastError()); return 0; }
#ifdef WIN98
// under Win9x, the client needs a running server to use callback
// notifications. This assumption is Ok, since only OLE uses
// callbacks, and in OLE every process is both client and server
RpcStatus = RpcServerUseProtseqEp("ncalrpc", 1, "dummy", NULL); if (RpcStatus != RPC_S_OK) return 0;
RpcStatus = RpcServerRegisterIf(&DummyInterfaceInformation, NULL, NULL); if (RpcStatus != RPC_S_OK) return 0;
RpcStatus = RpcServerListen(1, 2, TRUE); if (RpcStatus != RPC_S_OK) return 0;
#endif
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
pAsync->NotificationType = RpcNotificationTypeCallback; pAsync->u.NotificationRoutine = AsyncCallbackProc; // just a little bit of a hack. We know that the we cannot use
// the hEvent data member of u as we wished, because it occupies
// the same memory location as the callback routine, so we
// use the APC.hThread member which occupies the same DWORD
pAsync->u.APC.hThread = hEvent;
AsyncNullCall(pAsync, *b); WaitForSingleObject(hEvent, INFINITE); RpcAsyncCompleteCall(pAsync, NULL); }
CloseHandle(hEvent); nTiming = FinishTiming();
#ifdef WIN98
RpcStatus = RpcMgmtStopServerListening(NULL); if (RpcStatus == RPC_S_OK) { RpcMgmtWaitServerListen(); } #endif
return nTiming; }
unsigned long DoAsyncNullCallWithNone(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { RPC_STATUS RpcStatus;
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
pAsync->NotificationType = RpcNotificationTypeNone;
AsyncNullCall(pAsync, *b); // make sure we catch even the slightest variations in performance. Loop all the time ...
while (RpcAsyncGetCallStatus(pAsync) == RPC_S_ASYNC_CALL_PENDING) ; RpcAsyncCompleteCall(pAsync, NULL); }
return (FinishTiming()); }
unsigned long DoAsyncNullCallWithHwnd(IN PRPC_ASYNC_STATE pAsync, handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { RPC_STATUS RpcStatus; HWND hWnd = pAsync->u.HWND.hWnd;
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(pAsync, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
pAsync->NotificationType = RpcNotificationTypeHwnd; pAsync->u.HWND.hWnd = hWnd; pAsync->u.HWND.Msg = PERF_TEST_NOTIFY;
AsyncNullCall(pAsync, *b); PumpMessage(); RpcAsyncCompleteCall(pAsync, NULL); }
return (FinishTiming()); }
unsigned long DoAsyncNullCall(handle_t __RPC_FAR * b, long i, char __RPC_FAR *p) { RPC_ASYNC_STATE asyncState; RPC_STATUS RpcStatus; BOOL fCallComplete = FALSE;
RpcStatus = RpcAsyncInitializeHandle(&asyncState, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
asyncState.NotificationType = NotificationType;
switch (NotificationType) { case RpcNotificationTypeEvent: asyncState.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (asyncState.u.hEvent == NULL) { printf("CreateEvent failed: %ld\n", GetLastError()); return 0; } return DoAsyncNullCallWithEvent(&asyncState, b, i, p);
case RpcNotificationTypeApc: return DoAsyncNullCallWithApc(&asyncState, b, i, p);
case RpcNotificationTypeNone: return DoAsyncNullCallWithNone(&asyncState, b, i, p);
case RpcNotificationTypeHwnd: asyncState.u.HWND.hWnd = CreateSTAWindow("Noname"); if (asyncState.u.HWND.hWnd == NULL) { printf("CreateEvent failed: %ld\n", GetLastError()); return 0; } asyncState.u.HWND.Msg = PERF_TEST_NOTIFY; return DoAsyncNullCallWithHwnd(&asyncState, b, i, p);
case RpcNotificationTypeCallback: return DoAsyncNullCallWithCallback(&asyncState, b, i, p); default: printf("Invalid Notification option\n"); return FALSE; } }
unsigned long DoAsyncSTANullCall(handle_t __RPC_FAR * b, HWND hWnd, long i, char __RPC_FAR *p) { RPC_STATUS RpcStatus; RPC_ASYNC_STATE asyncState;
StartTime();
while(i--) { RpcStatus = RpcAsyncInitializeHandle(&asyncState, RPC_ASYNC_VERSION_1_0);
if (RpcStatus != RPC_S_OK) { printf("RpcAsyncInitializeHandle failed: %ld\n", GetLastError()); return 0; }
asyncState.NotificationType = RpcNotificationTypeCallback; asyncState.u.NotificationRoutine = NotifyProc;
AsyncSTANullCall(&asyncState, *b); PumpMessage(); RpcAsyncCompleteCall(&asyncState, NULL); }
return (FinishTiming()); }
static const unsigned long (*TestTable[TEST_MAX])(handle_t __RPC_FAR *, long, char __RPC_FAR *) = { DoNullCall, DoNICall, DoWrite1K, DoRead1K, DoWrite4K, DoRead4K, DoWrite32K, DoRead32K, DoContextNullCall, DoFixedBinding, DoReBinding, DoDynamicBinding, DoAsyncNullCall #ifdef WIN98
, DoAsyncSTANullCall #endif
};
//
// Worker calls the correct tests. Maybe multithreaded on NT
//
unsigned long Worker(unsigned long l) { unsigned long status; unsigned long lTest; long lIterations, lClientId; unsigned long lTime; char __RPC_FAR *pBuffer; char __RPC_FAR *stringBinding; handle_t binding; #ifdef WIN98
BOOL fIsPortseqWmsg; HWND hWnd; HWND hServerWnd; DWORD dwServerTid; #endif
#ifdef WIN98
if (strcmp(Protseq, "mswmsg") == 0) { fIsPortseqWmsg = TRUE; hWnd = CreateSTAWindow("Perf Client"); if (hWnd == NULL) { printf("Couldn't create STA window: %ld\n", GetLastError()); return 0; }
status = I_RpcServerStartListening(hWnd); if (status != RPC_S_OK) { printf("Failed to I_RpcServerStartListening: %ld\n", status); return 0; } } else fIsPortseqWmsg = FALSE; #endif
pBuffer = MIDL_user_allocate(32*1024L); if (pBuffer == 0) { PrintToConsole("Out of memory!"); return 1; }
status = RpcStringBindingCompose(0, Protseq, NetworkAddr, Endpoint, 0, &stringBinding); CHECK_RET(status, "RpcStringBindingCompose");
status = RpcBindingFromStringBinding(stringBinding, &binding); CHECK_RET(status, "RpcBindingFromStringBinding");
status = DoRpcBindingSetAuthInfo(binding); CHECK_RET(status, "RpcBindingSetAuthInfo");
RpcStringFree(&stringBinding);
#ifdef WIN98
if (fIsPortseqWmsg == TRUE) { while (TRUE) { hServerWnd = FindWindow(NULL, "Perf Server"); if (hServerWnd) { dwServerTid = (DWORD)GetWindowLong(hServerWnd, GWL_USERDATA); break; } printf("."); Sleep(100); }
status = I_RpcBindingSetAsync(binding, NULL, dwServerTid); if (status != RPC_S_OK) { printf("Failed to I_RpcBindingSetAsync: %ld\n", status); return 0; }
PrintToConsole("(%ld iterations of case %ld: ", 10000, 13);
lTime = DoAsyncSTANullCall(&binding, hWnd, 10000, pBuffer);
PrintToConsole("%ld mseconds)\n", lTime );
return RPC_S_OK; } #endif
RpcTryExcept { status = BeginTest(binding, &lClientId); } RpcExcept(1) { PrintToConsole("First call failed %ld (%08lx)\n", (unsigned long)RpcExceptionCode(), (unsigned long)RpcExceptionCode()); goto Cleanup; } RpcEndExcept
if (status == PERF_TOO_MANY_CLIENTS) { PrintToConsole("Too many clients, I'm exiting\n"); goto Cleanup ; } CHECK_RET(status, "ClientConnect");
PrintToConsole("Client %ld connected\n", lClientId);
do { status = NextTest(binding, (TEST_TYPE *)&lTest, &lIterations);
if (status == PERF_TESTS_DONE) { goto Cleanup; }
CHECK_RET(status, "NextTest");
PrintToConsole("(%ld iterations of case %ld: ", lIterations, lTest);
RpcTryExcept {
lTime = ( (TestTable[lTest])(&binding, lIterations, pBuffer));
PrintToConsole("%ld mseconds)\n", lTime );
status = EndTest(binding, lTime);
CHECK_RET(status, "EndTest");
} RpcExcept(1) { PrintToConsole("\nTest case %ld raised exception %lu (0x%08lX)\n", lTest, (unsigned long)RpcExceptionCode(), (unsigned long)RpcExceptionCode()); status = RpcExceptionCode(); } RpcEndExcept
} while(status == 0);
Cleanup: RpcBindingFree(&binding) ; return status; }
//
// The Win32 main starts worker threads, otherwise we just call the worker.
//
#ifdef WIN32
int __cdecl main (int argc, char **argv) { char option; unsigned long status, i; HANDLE *pClientThreads; #ifdef WIN98
BOOL fIsPortseqWmsg; #endif
ParseArgv(argc, argv);
PrintToConsole("Authentication Level is: %s\n", AuthnLevelStr);
if (Options[0] < 0) Options[0] = 1;
InitAllocator();
#ifdef WIN98
if (strcmp(Protseq, "mswmsg") == 0) { fIsPortseqWmsg = TRUE;
status = RpcServerUseProtseqEp(Protseq, 1, "Perf Client", NULL); if (status != RPC_S_OK) { printf("Failed to use protseq: %ld\n", status); return 3; } } else fIsPortseqWmsg = FALSE; #endif
pClientThreads = MIDL_user_allocate(sizeof(HANDLE) * Options[0]);
for(i = 0; i < (unsigned long)Options[0]; i++) { pClientThreads[i] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Worker, 0, 0, &status); if (pClientThreads[i] == 0) ApiError("CreateThread", GetLastError()); }
status = WaitForMultipleObjects(Options[0], pClientThreads, TRUE, // Wait for all client threads
INFINITE); if (status == WAIT_FAILED) { ApiError("WaitForMultipleObjects", GetLastError()); }
PrintToConsole("TEST DONE\n"); return(0); } #else // !WIN32
#ifdef WIN
#define main c_main
// We need the following to force the linker to load WinMain from the
// Windows STDIO library
extern int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int); static int (PASCAL *wm_ptr)(HANDLE, HANDLE, LPSTR, int) = WinMain;
#endif
#ifndef MAC
#ifndef FAR
#define FAR __far
#endif
#else
#define FAR
#define main c_main
#endif
int main (int argc, char FAR * FAR * argv) { #ifndef MAC
ParseArgv(argc, argv); #endif
Worker(0);
PrintToConsole("TEST DONE\n");
return(0); } #endif // NTENV
|