402 lines
9.5 KiB
C
402 lines
9.5 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (C) Microsoft Corporation, 1994-1999
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
RtSvr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Server side of RPC runtime scale performance test.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Mario Goertzel (mariogo) 31-Mar-1994
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
18/7/96 [MarioGo] - cloned from rpcrt test server.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <rpcperf.h>
|
||
|
#include <rpcrt.h>
|
||
|
|
||
|
// Usage
|
||
|
const char *USAGE =
|
||
|
"[-i iterations] -r [report interval] [-l logfile] [-n clients] [-n minthreads] [-n case]\n"
|
||
|
" Iterations - 4\n"
|
||
|
" Report - 15 seconds\n"
|
||
|
" Clients - default 1\n"
|
||
|
" MinThreads - default 3\n"
|
||
|
" Cases, you may specify one, default is 1:\n"
|
||
|
" 1: Null Call\n"
|
||
|
" 2: Null Call (Non-Idem)\n"
|
||
|
" 3: Buffers Call\n"
|
||
|
" Add [-n in size], [-n out size], defaults of 500 in/out\n"
|
||
|
" 4: Maybe Call\n"
|
||
|
" 5: Bind and Call\n"
|
||
|
"\n"
|
||
|
;
|
||
|
|
||
|
//
|
||
|
// Globals making it easier.
|
||
|
//
|
||
|
|
||
|
|
||
|
BOOL fClientsGoHome = FALSE;
|
||
|
|
||
|
long Clients, ActiveClients, ClientsLeft;
|
||
|
|
||
|
DWORD TestCase = 1;
|
||
|
DWORD InSize = 500;
|
||
|
DWORD OutSize = 500;
|
||
|
|
||
|
CRITICAL_SECTION CritSec;
|
||
|
HANDLE GoEvent = 0;
|
||
|
|
||
|
#define RPC_PH_KEEP_STATS 100
|
||
|
#define RPC_PH_ACCOUNT_FOR_MAX_CALLS 101
|
||
|
|
||
|
#ifdef STATS
|
||
|
BOOL RPCRTAPI RPC_ENTRY RpcSetPerformanceHint(int PerformanceHint, void *pValue);
|
||
|
#endif
|
||
|
|
||
|
char *TestNames[TEST_MAX] =
|
||
|
{
|
||
|
"Void Call\n",
|
||
|
"Void Call (non-idem)\n",
|
||
|
"Buffer Call %d (in) %d (out)\n",
|
||
|
"Maybe Calls\n",
|
||
|
"Bind calls\n"
|
||
|
};
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
DWORD dwRequestsProcessed;
|
||
|
} CLIENT_STATE;
|
||
|
|
||
|
CLIENT_STATE *ClientState;
|
||
|
|
||
|
#ifdef STATS
|
||
|
// exported by RPCRT4
|
||
|
void I_RpcGetStats(DWORD *pdwStat1, DWORD *pdwStat2, DWORD *pdwStat3, DWORD *pdwStat4);
|
||
|
#endif
|
||
|
|
||
|
void WhackReg(void);
|
||
|
|
||
|
//
|
||
|
// Figure out what we're testing and start listening.
|
||
|
//
|
||
|
|
||
|
int __cdecl
|
||
|
main (int argc, char **argv)
|
||
|
{
|
||
|
unsigned int MinThreads;
|
||
|
unsigned long i, j, status;
|
||
|
RPC_BINDING_VECTOR *pBindingVector;
|
||
|
SYSTEMTIME localTime;
|
||
|
OSVERSIONINFO verInfo;
|
||
|
|
||
|
DWORD StartCalls, FinalCalls, TotalCalls, TotalTicks, MinCalls, MaxCalls;
|
||
|
DWORD dwStat1, dwStat2, dwStat3, dwStat4;
|
||
|
|
||
|
InitAllocator();
|
||
|
|
||
|
ParseArgv(argc, argv);
|
||
|
|
||
|
MinThreads = 3;
|
||
|
ClientsLeft = Clients = 1;
|
||
|
ActiveClients = 0;
|
||
|
|
||
|
// DoTest();
|
||
|
|
||
|
if (Options[0] > 0)
|
||
|
ClientsLeft = Clients = Options[0];
|
||
|
|
||
|
ClientState = MIDL_user_allocate(sizeof(CLIENT_STATE) * Clients);
|
||
|
ZeroMemory(ClientState, sizeof(CLIENT_STATE) * Clients);
|
||
|
|
||
|
if (Options[1] > 0)
|
||
|
MinThreads = Options[1];
|
||
|
|
||
|
if (Options[2] < 0)
|
||
|
{
|
||
|
TestCase = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TestCase = Options[2];
|
||
|
if (TestCase < 1 || TestCase > TEST_MAX)
|
||
|
{
|
||
|
printf("Error: test case %d out of range\n", Options[2]);
|
||
|
TestCase = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TestCase--;
|
||
|
|
||
|
#ifdef STATS
|
||
|
if (TestCase == 0)
|
||
|
{
|
||
|
BOOL fValue = FALSE;
|
||
|
RpcSetPerformanceHint(RPC_PH_KEEP_STATS, &fValue);
|
||
|
RpcSetPerformanceHint(RPC_PH_ACCOUNT_FOR_MAX_CALLS, &fValue);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (Iterations == 1000)
|
||
|
{
|
||
|
Iterations = 4;
|
||
|
}
|
||
|
|
||
|
if (Options[3] > 0)
|
||
|
{
|
||
|
InSize = Options[3];
|
||
|
}
|
||
|
|
||
|
if (Options[4] > 0)
|
||
|
{
|
||
|
OutSize = Options[4];
|
||
|
}
|
||
|
|
||
|
// if a log file is on, make the output a bit more log-file friendly
|
||
|
if (LogFileName)
|
||
|
{
|
||
|
GetLocalTime(&localTime);
|
||
|
Dump("\n\n\n**** Perf Test Run ****");
|
||
|
Dump("%d/%d/%d %d:%d:%d\n", localTime.wMonth, localTime.wDay, localTime.wYear,
|
||
|
localTime.wHour, localTime.wMinute, localTime.wSecond);
|
||
|
}
|
||
|
|
||
|
InitializeCriticalSection(&CritSec);
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
// NtCurrentTeb()->ReservedForNtRpc = (PVOID)1;
|
||
|
|
||
|
// WhackReg();
|
||
|
#endif
|
||
|
|
||
|
GoEvent = CreateEvent(0,
|
||
|
TRUE,
|
||
|
FALSE,
|
||
|
0);
|
||
|
|
||
|
//
|
||
|
// Actually start the server
|
||
|
//
|
||
|
|
||
|
if (Endpoint)
|
||
|
{
|
||
|
status = RpcServerUseProtseqEpA(Protseq, 300, Endpoint, 0);
|
||
|
CHECK_STATUS(status, "RpcServerUseProtseqEp");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char *string_binding;
|
||
|
|
||
|
status = RpcServerUseProtseqA(Protseq, 300, 0);
|
||
|
CHECK_STATUS(status, "RpcServerUseProtseqEp");
|
||
|
|
||
|
status = RpcServerInqBindings(&pBindingVector);
|
||
|
CHECK_STATUS(status, "RpcServerInqBindings");
|
||
|
|
||
|
status = RpcEpRegister(_RpcRuntimeScalePerf_v1_0_s_ifspec,
|
||
|
pBindingVector,
|
||
|
0,
|
||
|
0);
|
||
|
CHECK_STATUS(status, "RpcEpRegister");
|
||
|
|
||
|
status = RpcBindingToStringBindingA(pBindingVector->BindingH[0],
|
||
|
&string_binding);
|
||
|
CHECK_STATUS(status, "RpcBindingToStringBinding");
|
||
|
|
||
|
status = RpcStringBindingParseA(string_binding,
|
||
|
0, 0, 0, &Endpoint, 0);
|
||
|
|
||
|
CHECK_STATUS(status, "RpcStringBindingParse");
|
||
|
printf("Listening to %s:[%s]\n\n", Protseq, Endpoint);
|
||
|
}
|
||
|
|
||
|
status =
|
||
|
RpcServerRegisterIf(_RpcRuntimeScalePerf_v1_0_s_ifspec,0,0);
|
||
|
CHECK_STATUS(status, "RpcServerRegisterIf");
|
||
|
|
||
|
status = RpcServerRegisterAuthInfo(NULL,
|
||
|
RPC_C_AUTHN_WINNT,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
CHECK_STATUS(status, "RpcServerRegisterAuthInfo (NTLM)");
|
||
|
|
||
|
memset(&verInfo, 0, sizeof(verInfo));
|
||
|
verInfo.dwOSVersionInfoSize = sizeof(verInfo);
|
||
|
status = GetVersionEx(&verInfo);
|
||
|
if (status == FALSE)
|
||
|
{
|
||
|
printf("Couldn't get system version (%d) - exitting\n", GetLastError());
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
if ((verInfo.dwMajorVersion >= 5) && (verInfo.dwPlatformId == VER_PLATFORM_WIN32_NT))
|
||
|
{
|
||
|
status = RpcServerRegisterAuthInfo(NULL,
|
||
|
RPC_C_AUTHN_GSS_KERBEROS,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
CHECK_STATUS(status, "RpcServerRegisterAuthInfo (KERBEROS)");
|
||
|
|
||
|
status = RpcServerRegisterAuthInfo(NULL,
|
||
|
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
CHECK_STATUS(status, "RpcServerRegisterAuthInfo (SNEGO)");
|
||
|
}
|
||
|
|
||
|
printf("Clients %d, MinThreads %d\n",
|
||
|
Clients,
|
||
|
MinThreads);
|
||
|
|
||
|
printf("Server listening\n\n");
|
||
|
|
||
|
status = RpcServerListen(MinThreads, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
|
||
|
CHECK_STATUS(status, "RpcServerListen");
|
||
|
|
||
|
printf("Running test: ");
|
||
|
printf(TestNames[TestCase], InSize, OutSize);
|
||
|
|
||
|
WaitForSingleObject(GoEvent, INFINITE);
|
||
|
|
||
|
Sleep(1000);
|
||
|
|
||
|
// Collect and report results. Signal test shutdown when finished.
|
||
|
|
||
|
for (i = 0; i < Iterations; i++)
|
||
|
{
|
||
|
|
||
|
StartTime();
|
||
|
|
||
|
StartCalls = 0;
|
||
|
for (j = 0; j < (ULONG)Clients; j++ )
|
||
|
{
|
||
|
StartCalls += ClientState[j].dwRequestsProcessed;
|
||
|
}
|
||
|
|
||
|
Sleep(Interval * 1000);
|
||
|
|
||
|
FinalCalls = MaxCalls = 0;
|
||
|
MinCalls = ~0;
|
||
|
for (j = 0; j < (ULONG)Clients; j++)
|
||
|
{
|
||
|
DWORD t;
|
||
|
|
||
|
t = ClientState[j].dwRequestsProcessed;
|
||
|
|
||
|
FinalCalls += t;
|
||
|
|
||
|
if (t < MinCalls)
|
||
|
{
|
||
|
MinCalls = t;
|
||
|
}
|
||
|
if (t > MaxCalls)
|
||
|
{
|
||
|
MaxCalls = t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TotalCalls = FinalCalls - StartCalls;
|
||
|
|
||
|
TotalTicks = FinishTiming();
|
||
|
|
||
|
Dump("Ticks: %4d, Total: %4d, Average %4d, TPS %3d\n",
|
||
|
TotalTicks,
|
||
|
TotalCalls,
|
||
|
TotalCalls / Clients,
|
||
|
TotalCalls * 1000 / TotalTicks
|
||
|
);
|
||
|
|
||
|
Verbose("Max: %d, Min: %d\n", MaxCalls, MinCalls);
|
||
|
}
|
||
|
|
||
|
fClientsGoHome = TRUE;
|
||
|
|
||
|
Sleep(5000);
|
||
|
|
||
|
#ifdef STATS
|
||
|
I_RpcGetStats(&dwStat1, &dwStat2, &dwStat3, &dwStat4);
|
||
|
printf("Stats are: %ld, %ld, %ld, %ld\n", dwStat1, dwStat2, dwStat3, dwStat4);
|
||
|
#endif
|
||
|
|
||
|
printf("Test Complete\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Control APIs that the client(s) call to sync on test cases, iterations
|
||
|
// and to report results.
|
||
|
//
|
||
|
|
||
|
error_status_t
|
||
|
_BeginTest(handle_t b,
|
||
|
DWORD *ClientId,
|
||
|
DWORD *pTestCase,
|
||
|
DWORD *pInSize,
|
||
|
DWORD *pOutSize )
|
||
|
{
|
||
|
long status = 0;
|
||
|
|
||
|
EnterCriticalSection(&CritSec);
|
||
|
|
||
|
if (ActiveClients < Clients)
|
||
|
{
|
||
|
*ClientId = ActiveClients;
|
||
|
ActiveClients++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = PERF_TOO_MANY_CLIENTS;
|
||
|
}
|
||
|
LeaveCriticalSection(&CritSec);
|
||
|
|
||
|
*pTestCase = TestCase;
|
||
|
*pInSize = InSize;
|
||
|
*pOutSize = OutSize;
|
||
|
|
||
|
// Either wait for the rest of the clients or signal the clients to go.
|
||
|
if (status == 0)
|
||
|
{
|
||
|
if (*ClientId < (ULONG)Clients - 1 )
|
||
|
{
|
||
|
// WaitForSingleObject(GoEvent, INFINITE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetEvent(GoEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
#define TEST_BODY { ClientState[client].dwRequestsProcessed++; \
|
||
|
if (fClientsGoHome) return PERF_TESTS_DONE; \
|
||
|
return 0; \
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD _NullCall(handle_t h, DWORD client)
|
||
|
TEST_BODY
|
||
|
|
||
|
void _MaybeCall (handle_t h, DWORD client)
|
||
|
{
|
||
|
ClientState[client].dwRequestsProcessed++;
|
||
|
}
|
||
|
|
||
|
DWORD _NICall (handle_t h, DWORD client)
|
||
|
TEST_BODY
|
||
|
|
||
|
DWORD _BufferCall(handle_t h, DWORD client, long crq, byte inb[], long crp, byte outb[])
|
||
|
TEST_BODY
|
||
|
|