blob: ad9c34cf0a16a9b177d490258123a590eeed3451 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* xmpl_perf_client_tests.c
* test code invoked from [main]
*/
#include "xmpl_perf_client_main.h"
char* ETCHTEST = "TEST";
/**
* perftestobj
* perftest "class" instance data
*/
typedef struct perftestobj
{
unsigned sig;
char* descr;
wchar_t* uri;
int waitms;
int runtime;
int count;
int threads;
int iterations;
new_client_funcptr new_client; /* user's main() client constructor */
} perftestobj;
int testerrors;
etch_objsession_objinfo notifyinfo;
typedef int (*perftest_threadproc) (etch_threadparams*);
#define EXCEPTION_EXPECTED 1
#define NOTIFY_EXPECTED 2
#define PERFTESTOBJ_SIGNATURE 0xabaddeed
/* - - - - - - - - - - - - - - -
* support methods for tests
* - - - - - - - - - - - - - - -
*/
/**
* perf_xmpl_log_startmsg()
* log start of individual test.
*/
void perf_xmpl_log_startmsg (char* msgdescr)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "begin perf test message %s\n", msgdescr);
}
/**
* perf_xmpl_log_endmsg()
* log end of individual test.
*/
void perf_xmpl_log_endmsg (char* msgdescr, const int result)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "end message %s result %d\n", msgdescr, result);
}
/**
* perf_xmpl_log_startmsgex()
* log start of individual test.
*/
void perf_xmpl_log_startmsgex (char* msgdescr, const int count)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "begin %s count %d\n", msgdescr, count);
}
/**
* perf_xmpl_log_endmsgex()
* log end of individual test.
*/
void perf_xmpl_log_endmsgex (char* msgdescr, const int result, const int count)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "end %s count %d result %d\n", msgdescr, count, result);
}
/**
* perf_xmpl_log_objerr()
* log unexpected test response object type.
*/
void perf_xmpl_log_objerr (char* msgdescr)
{
etchlog(ETCHTEST, ETCHLOG_ERROR, "response for %s was not an expected object type\n", msgdescr);
testerrors++;
}
/**
* perf_xmpl_log_resulterr()
* log unexpected response object value.
*/
void perf_xmpl_log_resulterr (char* msgdescr)
{
etchlog(ETCHTEST, ETCHLOG_ERROR, "result value for %s was not the expected value\n", msgdescr);
testerrors++;
}
/**
* perf_xmpl_log_resultok()
* log expected response received
*/
void perf_xmpl_log_resultok (char* msgdescr, char* resultdescr)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "%s got expected result '%s'\n", msgdescr, resultdescr);
}
/**
* perf_xmpl_log_resultokex()
* log expected response received
*/
void perf_xmpl_log_resultokex (char* msgdescr)
{
etchlog(ETCHTEST, ETCHLOG_INFO, "%s got expected result\n", msgdescr);
}
/**
* perf_xmpl_validate_response_object()
* test response object for exception and log result.
*/
int perf_xmpl_validate_response_object (objmask* responseobj, const int is_excp_expected)
{
int result = -1;
if (is_excp_expected == NOTIFY_EXPECTED)
{
/* we need to let the receive thread run here, otherwise the session_notify()
* delivering the exception has not been called yet. this is a race condition
* in the java code, subsequently translated here. todo come up with a synch-
* ronization mechanism that will force the remote call to complete through
* either mailbox post and read, or session_notify(). */
etch_sleep(35); /* fyi 20ms is not enough */
if (notifyinfo.is_exception)
{
/* exception from 1-way message came back via overridden session_notify() */
etchlog(ETCHTEST, ETCHLOG_ERROR, "user got expected exception response\n");
result = 0;
}
else
etchlog(ETCHTEST, ETCHLOG_ERROR, "missing session_notify exception\n");
}
else
if (NULL == responseobj)
etchlog(ETCHTEST, ETCHLOG_ERROR, "user got null response\n");
else
if (is_exception(responseobj))
{
etchexception* x = get_exception_from (responseobj);
if (NULL == x)
etchlog(ETCHTEST, ETCHLOG_ERROR, "user got malformed exception\n");
else
{ char* txta = x->ansitext? x->ansitext: "<no text>";
if (is_excp_expected)
{ etchlog(ETCHTEST, ETCHLOG_ERROR, "user got expected exception '%s'\n", txta);
result = 0;
}
else
etchlog(ETCHTEST, ETCHLOG_ERROR, "user got exception response '%s'\n", txta);
}
}
else result = is_excp_expected? -1: 0;
return result;
}
/**
* perf_xmpl_wait_seconds()
* sleep for nseconds, displaying a dot either every second or every five seconds.
*/
void perf_xmpl_wait_seconds (int nseconds)
{
int is_showdot = 0;
const int is_longwait = nseconds > 20;
if (nseconds <= 0) return;
etchlog(ETCHTEST, ETCHLOG_INFO, "sleeping %d seconds per config ", nseconds);
while(nseconds--)
{ etch_sleep(1000);
is_showdot = is_longwait? nseconds % 5 == 0: TRUE;
if (is_showdot) printf(".");
}
printf("\n");
}
etch_session_notify old_session_notify;
void my_reset_notifyinfo() { memset(&notifyinfo, 0, sizeof(etch_objsession_objinfo)); }
/**
* etchsession_my_session_notify()
* override for client impl session_notify.
* this override will receive notifications of unsolicited messages from server,
* in particular exceptions returned from one-way messages.
* @param obj caller i_objsession*.
* @param evt some etch object or null. relinquished and destroyed here.
*/
int my_session_notify (void* obj, void* evt)
{
etchlog(ETCHTEST, ETCHLOG_DEBUG, "user received session_notify\n");
etchsession_get_objinfo (&notifyinfo, evt);
return old_session_notify (obj, evt); /* destroys evt object */
}
/**
* override_client_session_notify()
* override the client's default session_notify to be our own callback,
* which saves the properties of the notified object prior to destroying the object.
*/
void my_override_client_session_notify (perf_remote_server* rs)
{
etchlog(ETCHTEST, ETCHLOG_DEBUG, "user overrides session_notify\n");
old_session_notify = perf_remote_set_session_notify (rs, my_session_notify);
assert(old_session_notify);
}
/**
* restore_client_session_notify()
* restore the client's default session_notify to be the default callback,
*/
void my_restore_client_session_notify (perf_remote_server* rs)
{
assert(old_session_notify);
etchlog(ETCHTEST, ETCHLOG_DEBUG, "user restores session_notify\n");
perf_remote_set_session_notify (rs, old_session_notify);
}
/**
* perftest_get_params()
* extract the perftest params from the etch thread params and validate
*/
perftestobj* perftest_get_params(void* p)
{
perftestobj* outobj = NULL;
if (p && ((etch_threadparams*) p)->signature == ETCH_THREADPARAMS_SIGNATURE)
outobj = ((etch_threadparams*) p)->data;
assert(outobj && outobj->sig == PERFTESTOBJ_SIGNATURE);
return outobj;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* perftest_threadprocs for each server-directed service method test
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/* - - - - - - - - -
* perf.add()
* - - - - - - - - -
*/
/**
* perftest_threadproc_add
* perftest thread procedure for specific perf test "add"
*/
int perftest_threadproc_add (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
char* thistest = "perf.add";
/* create parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.add() n times */
{
etch_int32* resultobj = remote->add (remote, new_int32(1000000000), new_int32(2000000000));
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_etch_int32(resultobj))
if (resultobj->value == 3000000000)
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* stop and dispose of remote server */
/* note that if we omit the stop_waitdown() here, behavior is unchanged */
result = remote->remote_base->stop_waitdown (remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/**
* perftest_threadproc_add_async
* perftest thread procedure for specific perf test "add"
*/
int perftest_threadproc_add_async (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
/* create parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--)
{
etch_int32 *resultobj = NULL;
i_mailbox* mbox = NULL;
mbox = remote->async_begin_add (remote, new_int32(1000000000), new_int32(2000000000));
assert(mbox);
resultobj = remote->async_end_add (remote, mbox);
assert(resultobj);
ETCHOBJ_DESTROY(resultobj);
perf_remote_dispose_mailbox (remote, &mbox);
}
/* dispose of server */
result = remote->remote_base->stop_waitdown (remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - -
* perf.sum()
* - - - - - - - - -
*/
/**
* perftest_threadproc_sum
* perftest thread procedure for specific perf test "sum"
*/
int perftest_threadproc_sum (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
int values[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int numdims = 1, itemsize = sizeof(int), itemcount = sizeof(values)/itemsize;
char* thistest = "perf.sum";
/* create parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.sum() n times */
{
etch_nativearray* a = new_nativearray_from (values, CLASSID_ARRAY_INT32,
itemsize, numdims, itemcount, 0, 0);
etch_int32* resultobj = remote->sum (remote, (etch_arraytype*) a);
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_etch_int32(resultobj))
if (resultobj->value == 36)
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* stop and dispose of remote server */
/* note that if we omit the stop_waitdown() here, behavior is unchanged */
result = remote->remote_base->stop_waitdown (remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - -
* perf.report()
* - - - - - - - - -
*/
/**
* perftest_threadproc_report
* perftest thread procedure for specific perf test "sum"
*/
int perftest_threadproc_report (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
const int msgcode = 23;
wchar_t* msgtext = L"this message describes the specifics of code 23";
char* thistest = "perf.report";
/* create parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.report() n times */
{
etch_int32* resultobj = remote->report (remote, new_int32(msgcode), new_stringw(msgtext));
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_etch_int32(resultobj))
if (resultobj->value == 0)
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* dispose of server */
result = remote->remote_base->stop_waitdown(remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - -
* perf.dist()
* - - - - - - - - -
*/
/**
* perftest_threadproc_dist
* perftest thread procedure for specific perf test "dist"
*/
int perftest_threadproc_dist (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
const int a1 = 1, a2 = 2, b1 = 1000000000, b2 = 2000000000;
char* thistest = "perf.dist";
/* seed parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.dist() n times */
{
perf_point* resultobj = remote->dist (remote, new_perf_point(a1,a2), new_perf_point(b1,b2));
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_perf_point(resultobj))
if (resultobj->x && resultobj->y) /* todo check actual expected values here */
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* dispose of server */
/* note that if we omit the stop_waitdown() here, behavior is unchanged */
result = remote->remote_base->stop_waitdown(remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - -
* perf.add2()
* - - - - - - - - -
*/
/**
* perftest_threadproc_add2
* perftest thread procedure for specific perf test "add2"
*/
int perftest_threadproc_add2 (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
const int64 adjsecs = 365*24*60*60, adjms = adjsecs * 1000; /* 1 year */
char* thistest = "perf.add2";
/* seed parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.dist() n times */
{
etch_date* resultobj = remote->add2 (remote, new_date(), new_int64(adjms));
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_etch_date(resultobj))
if (resultobj->value) /* todo check actual expected value here */
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* dispose of server */
result = remote->remote_base->stop_waitdown(remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - -
* perf.report2()
* - - - - - - - - -
*/
/**
* perftest_threadproc_report2
* perftest thread procedure for specific perf test "report2"
*/
int perftest_threadproc_report2 (etch_threadparams* tp)
{
perftestobj* p = perftest_get_params(tp);
int result = 0, iterations = p->iterations;
const int msgcode = 23;
wchar_t* msgtext = L"this message describes the specifics of code 23";
char* thistest = "perf.report2";
/* seed parameter bundle with callback to editable client constructor */
etch_client_factory* impl_factory = new_client_factory (NULL, NULL, p->new_client);
/* instantiate a remote server, which invokes client constructor */
perf_remote_server* remote = new_remote_server (p->uri, impl_factory);
assert(remote);
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
/* wait for server to come up */
result = remote->remote_base->start_waitup (remote->remote_base, p->waitms);
assert(0 == result);
while(iterations--) /* execute perf.dist() n times */
{
etch_int32* resultobj = remote->report2 (remote,
new_date(), new_int32(msgcode), new_stringw(msgtext));
if (0 == (result = perf_xmpl_validate_response_object ((objmask*)resultobj, 0)))
if (is_etch_int32(resultobj))
if (resultobj->value == 0)
perf_xmpl_log_resultokex(thistest);
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
ETCHOBJ_DESTROY(resultobj);
}
/* dispose of server */
result = remote->remote_base->stop_waitdown(remote->remote_base, p->waitms);
assert(0 == result);
ETCHOBJ_DESTROY(remote);
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* thread runners: execute specified test threadproc on specified number of threads
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/**
* perftest_run_unthreaded()
* general perftest main thread runner.
*/
void perftest_run_unthreaded (perftestobj* p, perftest_threadproc runner)
{
etch_threadparams threadparams; etch_init_threadparams(&threadparams);
threadparams.data = p;
etchlog(ETCHTEST, ETCHLOG_INFO, "RUNNING %s on MAIN THREAD\n", p->descr);
runner(&threadparams);
}
/**
* perftest_run_threads()
* general perftest concurrent test runner.
* @param p the test data object, not owned here.
*/
void perftest_run_threads (perftestobj* p, perftest_threadproc runner)
{
int i = 0;
etch_thread* newthread = 0;
etch_threadpool* pool = new_threadpool(ETCH_THREADPOOLTYPE_FREE, p->threads);
pool->is_free_data = FALSE; /* prevent thread from destroying the perftestobj */
etchlog(ETCHTEST, ETCHLOG_INFO, "RUNNING %s ON %d THREADS\n", p->descr, p->threads);
for(; i < p->threads; i++) /* launch the requested number of tests */
{ /* note that the pool threads are started immediately by default.
* if we wanted to instead start them explicitly, we would have
* set pool->is_manual_start true, above, and later called
* newthread->start(newthread);
*/
etchlog(ETCHTEST, ETCHLOG_INFO, "STARTING %s ON THREAD %d\n", p->descr, i);
newthread = pool->run (pool, runner, p);
assert(newthread);
}
/* wait for all active pool threads to exit, and finally free memory */
pool->destroy(pool);
}
/**
* perftest_run_one()
* general perftest single test runner.
*/
double perftest_run_one (perftestobj* p, const int n, perftest_threadproc run)
{
int64 t0 = etch_system_nanotime(), t1 = 0;
p->iterations = n;
if (p->threads <= 1)
perftest_run_unthreaded(p, run);
else
perftest_run_threads(p, run);
t1 = etch_system_nanotime();
return (t1 - t0) / (double) 1000000000;
}
/* - - - - - - - - - - - - - - - - - - - - - - - -
* test runner: per-service-method test execution
* - - - - - - - - - - - - - - - - - - - - - - - -
*/
/**
* run_perftest()
* combines java perftest constructor and java perftest.run()
*/
int run_perftest (char* descr, wchar_t* uri, const int waitms, const int runtime,
const int count, const int threads, perftest_threadproc testproc,
new_client_funcptr new_perfclient)
{
char* mask = NULL;
perftestobj perftest;
etch_arraylist* list = NULL;
double time = 0.0, sum = 0.0, r = 0.0;
int result = 0, k = 0, oldn = 0, n = 1, i = 0, times = 0;
memset (&perftest, 0, sizeof(perftestobj));
perftest.sig = PERFTESTOBJ_SIGNATURE;
perftest.count = count;
perftest.descr = descr;
perftest.uri = uri;
perftest.runtime = runtime;
perftest.threads = threads;
perftest.waitms = waitms;
perftest.new_client = new_perfclient;
/* use this to temporarily test run_one */
/* perftest_run_one (&perftest, n, testproc); */
mask = "%s %d took %f -- trying %d to get >= 1 second\n";
while(time < 1.0)
{
if (time > 0.1)
etchlog(ETCHTEST, ETCHLOG_INFO, mask, descr, oldn, time, n);
oldn = n;
time = perftest_run_one (&perftest, n, testproc);
etchlog(ETCHTEST, ETCHLOG_INFO, "****** run_one time result is %f\n", time);
n *= 2;
if (++times > 10) // failsafe loop exit
{ etchlog(ETCHTEST, ETCHLOG_INFO, "exiting run loop after max 10 times\n");
break;
}
}
n = oldn;
#if(0)
k = 2;
n = (int) ((k * n) / time);
mask = "%s %d took %f -- trying %d for %d seconds\n";
etchlog(ETCHTEST, ETCHLOG_INFO, mask, descr, oldn, time, n, k);
oldn = n;
time = perftest_run_one(&perftest, n, testproc);
k = 4;
n = (int) ((k * n) / time);
mask = "%s %d took %f -- trying %d for %d seconds\n";
etchlog(ETCHTEST, ETCHLOG_INFO, mask, descr, oldn, time, n, k);
oldn = n;
time = perftest_run_one(&perftest, n, testproc);
n = (int) ((runtime * n) / time);
mask = "%s %d took %f -- using %d for %d seconds\n";
etchlog(ETCHTEST, ETCHLOG_INFO, mask, descr, oldn, time, n, runtime);
list = new_arraylist(count, 0);
list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
mask = "%s %d/%d\t%d\t%d\t%f\t%f\t%f\n";
for(i = 0; i < count; i++)
{
time = perftest_run_one(&perftest, n, testproc);
sum += (r = n / time);
arraylist_add(list, new_double(r));
etchlog(ETCHTEST, ETCHLOG_INFO, mask, descr, i, count, threads,
n, time, r, r*threads);
}
#endif
/* todo: calculate and display min, max, media, mean */
ETCHOBJ_DESTROY(list);
return 0;
}
/**
* perf_xmpl_verify_server()
* ensure server is working.
* @return count of failed tests.
*/
int perf_xmpl_verify_server (perf_remote_server* remote)
{
char* thistest = NULL;
int testresult = 0;
/* redirect session notifications to here in order to catch exceptions
* returned from one-way messages. */
my_override_client_session_notify (remote);
#if(1)
do /* perf.add() */
{ etch_int32* addresult;
perf_xmpl_log_startmsg (thistest = "perf.add 1");
/* execute the remote add() call 2 + 3 */
/* arguments objects are relinquished, result object is assumed */
addresult = remote->add (remote, new_int32(2), new_int32(3));
if (0 == (testresult = perf_xmpl_validate_response_object ((objmask*)addresult, 0)))
if (is_etch_int32(addresult))
if (addresult->value == 5)
perf_xmpl_log_resultok(thistest, "2 + 3 = 5");
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(addresult);
} while(0);
#endif
#if(1)
do /* perf.add() negative test */
{ etch_int32* addresult;
perf_xmpl_log_startmsg (thistest = "perf.add 2");
/* this test sends a bad object type (float) to perf.add().
* the result of this test will differ depending on whether validation
* is enabled on output. if so, an illegal arg exception should be thrown
* at the client which user will see. if not, serialization will fail at
* the server due to the validation error, server will not return a
* perf.add result, and user should see a timeout exception.
*/
/* execute the remote add() call with invalid object types */
/* arguments objects are relinquished, result object is assumed */
addresult = remote->add (remote, (etch_int32*) new_int32(2), (etch_int32*) new_float(3));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)addresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(addresult);
} while(0);
#endif
#if(1)
do /* perf.add() negative test */
{ etch_int32* addresult;
perf_xmpl_log_startmsg (thistest = "perf.add 3");
/* this test sends a certain integer value to perf.add() which the server
* implementation is coded to interpret as bad data for which it should
* throw an exception. the exception should be serialized back across the
* wire and user should see the exception.
*/
/* execute the remote add() call with invalid object types */
/* arguments objects are relinquished, result object is assumed */
addresult = remote->add (remote, (etch_int32*)
new_int32(FAKEBADDATA_INT32),(etch_int32*) new_int32(3));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)addresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(addresult);
} while(0);
#endif
#if(1)
do /* perf.sum() nativearray */
{ const int ITEMSIZE = sizeof(int), NUMDIMS = 1, NUMITEMS = 3;
const int DIM0 = NUMITEMS, DIM1 = 0, DIM2 = 0;
int ival0 = 1, ival1 = 2, ival2 = 3;
etch_int32* sumresult;
etch_nativearray* myarray;
perf_xmpl_log_startmsg (thistest = "perf.sum 1");
myarray = new_nativearray(CLASSID_ARRAY_INT32, sizeof(int), NUMDIMS, DIM0, DIM1, DIM2);
myarray->put1(myarray, &ival0, 0);
myarray->put1(myarray, &ival1, 1);
myarray->put1(myarray, &ival2, 2);
/* execute the remote sum() call */
/* arguments objects are relinquished, result object is assumed */
sumresult = remote->sum (remote, (etch_arraytype*) myarray);
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)sumresult, 0)))
if (is_etch_int32(sumresult))
if (sumresult->value == 6)
perf_xmpl_log_resultok(thistest, "sum(1,2,3)=6");
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(sumresult);
} while(0);
#endif
#if(1)
do /* perf.sum() arrayvalue */
{ etch_int32* sumresult;
etch_arrayvalue* myarray;
perf_xmpl_log_startmsg (thistest = "perf.sum 2");
myarray = new_arrayvalue (ETCH_XTRNL_TYPECODE_INT, NULL, 1, 4, 4, FALSE, FALSE);
arrayvalue_add(myarray, (etch_object*) new_int32(1));
arrayvalue_add(myarray, (etch_object*) new_int32(2));
arrayvalue_add(myarray, (etch_object*) new_int32(3));
/* execute the remote sum() call */
/* arguments objects are relinquished, result object is assumed */
sumresult = remote->sum (remote, (etch_arraytype*) myarray);
if (0 == (testresult = perf_xmpl_validate_response_object((objmask*)sumresult, 0)))
if (is_etch_int32(sumresult))
if (sumresult->value == 6)
perf_xmpl_log_resultok(thistest, "sum(1,2,3)=6");
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(sumresult);
} while(0);
#endif
#if(1)
do /* perf.sum() negative - bad array object */
{ etch_int32 *sumresult, *not_an_array = new_int32(0);
perf_xmpl_log_startmsg (thistest = "perf.sum 3");
/* execute the remote sum() call
* arguments objects are relinquished, result object is assumed
* if validate on write is on, we expect a validation error at the client.
* if validate on write is off, we expect no result from server due to the
* resulting deserialization error, and a timeout exception at the client
*/
sumresult = remote->sum (remote, (etch_arraytype*) not_an_array);
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)sumresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(sumresult);
} while(0);
#endif
#if(1)
do /* perf.sum() negative - bad array value */
{ const int ITEMSIZE = sizeof(int), NUMDIMS = 1, NUMITEMS = 3;
const int DIM0 = NUMITEMS, DIM1 = 0, DIM2 = 0;
int ival0 = 1, ival1 = FAKEBADDATA_INT32, ival2 = 3; /* <=== BAD DATA */
etch_int32* sumresult;
etch_nativearray* myarray;
perf_xmpl_log_startmsg (thistest = "perf.sum 4");
myarray = new_nativearray(CLASSID_ARRAY_INT32, sizeof(int), NUMDIMS, DIM0, DIM1, DIM2);
myarray->put1(myarray, &ival0, 0);
myarray->put1(myarray, &ival1, 1);
myarray->put1(myarray, &ival2, 2);
/* execute the remote sum() call
* arguments objects are relinquished, result object is assumed
* we expect to get an illegal argument exception back from the server here.
*/
sumresult = remote->sum (remote, (etch_arraytype*) myarray);
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)sumresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(sumresult);
} while(0);
#endif
#if(1)
do /* perf.report() */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report 1");
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/
represult = remote->report (remote, new_int32(18), new_stringw(L"starting"));
testresult = perf_xmpl_validate_response_object ((objmask*)represult, 0);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
#if(1)
do /* perf.report() negative - bad parameter object */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report 2");
my_reset_notifyinfo();
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/ /* double is bad param here */
represult = remote->report (remote, (etch_int32*) new_double(0), new_stringw(L"it works!"));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)represult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
#if(1)
do /* perf.report() negative - bad data */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report 3");
my_reset_notifyinfo();
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/ /* FAKEBADDATA_STRING is bad data */
represult = remote->report (remote, new_int32(18), new_stringw(FAKEBADDATA_STRING));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)represult, NOTIFY_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
#if(1)
do /* perf.dist() */
{ perf_point* distresult;
perf_xmpl_log_startmsg (thistest = "perf.dist 1");
/* execute the remote dist() call dist(point(1,2), point(3,5)) */
/* arguments objects are relinquished, result object is assumed */
distresult = remote->dist (remote, new_perf_point(1,2), new_perf_point(3,5));
if (0 == (testresult = perf_xmpl_validate_response_object((objmask*)distresult, 0)))
if (is_perf_point(distresult))
if (distresult->x == 2 && distresult->y == 3)
perf_xmpl_log_resultok (thistest, "dist((1,2),(3,5)) = (2,3)");
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(distresult);
} while(0);
#endif
#if(1)
do /* perf.dist() negative - bad parameter type */
{ perf_point* distresult;
perf_xmpl_log_startmsg (thistest = "perf.dist 2");
/* execute the remote dist() call dist(point(1,2), point(3,5)) */
/* arguments objects are relinquished, result object is assumed */
distresult = remote->dist (remote, new_perf_point(1,2), (perf_point*) new_structvalue(NULL, 0));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)distresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(distresult);
} while(0);
#endif
#if(1)
do /* perf.dist() negative - bad parameter value */
{ perf_point* distresult;
perf_xmpl_log_startmsg (thistest = "perf.dist 3");
/* execute the remote dist() call dist(point(1,2), point(3,5)) */
/* arguments objects are relinquished, result object is assumed */
distresult = remote->dist (remote, new_perf_point(1,2), new_perf_point(1, FAKEBADDATA_INT32));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)distresult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(distresult);
} while(0);
#endif
#if(1)
do /* perf.add2() */
{ etch_date* add2result;
const int64 adjms = 3600000;
etch_date* now = new_date();
/* for this test, save date value for verify below, since date object relinquished */
const time_t oldtime = now->value;
perf_xmpl_log_startmsg (thistest = "perf.add2 1");
/* execute the remote add2() call add2(date, msecs) */
/* arguments objects are relinquished, result object is assumed */
add2result = remote->add2(remote, now, new_int64(adjms));
if (0 == (testresult = perf_xmpl_validate_response_object((objmask*)add2result, 0)))
if (is_etch_date(add2result))
if (add2result && !is_exception(add2result))
{ const time_t newtime = add2result->value; /* time_t is in seconds */
const int64 adjsecs = adjms / 1000; /* so convert ms to seconds */
const int64 chktime = newtime - adjsecs;
if (chktime == oldtime)
perf_xmpl_log_resultok (thistest, "for add2(now, 3600000ms)");
else perf_xmpl_log_resulterr(thistest);
}
else perf_xmpl_log_resulterr(thistest);
else perf_xmpl_log_objerr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(add2result);
} while(0);
#endif
#if(1)
do /* perf.add2() negative - bad parameter type */
{ etch_date* add2result;
perf_xmpl_log_startmsg (thistest = "perf.add2 2");
/* execute the remote add2() */
/* arguments objects are relinquished, result object is assumed */
add2result = remote->add2(remote, (etch_date*) new_double(0), new_int64(0));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)add2result, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(add2result);
} while(0);
#endif
#if(1)
do /* perf.add2() negative - bad data value */
{ etch_date* add2result, *bad_date = new_date();
bad_date->value = FAKEBADDATA_DATE;
perf_xmpl_log_startmsg (thistest = "perf.add2 3");
/* execute the remote add2() */
/* arguments objects are relinquished, result object is assumed */
add2result = remote->add2(remote, bad_date, new_int64(0));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)add2result, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(add2result);
} while(0);
#endif
#if(1)
do /* perf.report2() */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report2 1");
my_reset_notifyinfo();
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/
represult = remote->report2 (remote, new_date(), new_int32(18), new_stringw(L"x"));
testresult = perf_xmpl_validate_response_object ((objmask*)represult, 0);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
#if(1)
do /* perf.report2() negative - bad parameter type */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report2 2");
my_reset_notifyinfo();
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/
represult = remote->report2 (remote, new_date(), new_int32(18), (etch_string*) new_int32(0));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)represult, EXCEPTION_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
#if(1)
do /* perf.report2() negative - bad data value */
{ objmask* represult = NULL;
perf_xmpl_log_startmsg (thistest = "perf.report2 3");
my_reset_notifyinfo();
/* execute the remote report() call.
* arguments objects are relinquished, result object is assumed.
* this service method has no return type, however c binding always
* returns an object shell in order to host a possible exception.
*/
represult = remote->report2 (remote, new_date(), new_int32(18), new_stringw(FAKEBADDATA_STRING));
if (0 != (testresult = perf_xmpl_validate_response_object((objmask*)represult, NOTIFY_EXPECTED)))
perf_xmpl_log_resulterr(thistest);
perf_xmpl_log_endmsg (thistest, testresult);
ETCHOBJ_DESTROY(represult);
} while(0);
#endif
/* we sleep briefly here since if the last message was one-way, we will have
* not waited for a result, and if we now close the client socket before the
* server has had a chance to run the message, the server would detect the
* closed socket and shut down the client session, possibly prior to running
* the message implementation, and that test would therefore be incomplete.
* NOTE that if we are stepping though the server in the debugger, we should
* set config.sleepSecondsPriorClientExit to a sufficient number of seconds
* such that the client socket will not close while doing so.
*/
etch_sleep(500);
perf_xmpl_wait_seconds (config.sleepSecondsPriorClientExit);
if (testerrors)
etchlog(ETCHTEST, ETCHLOG_ERROR, "perf_xmpl_verify_server %d PERF TESTS FAILED\n", testerrors);
else
etchlog(ETCHTEST, ETCHLOG_INFO, "perf_xmpl_verify_server ALL PERF TESTS PASS\n");
my_restore_client_session_notify (remote);
return testerrors;
}
/* - - - - - - - - - - - - - - - - - - - - -
* call from main() to run all tests
* - - - - - - - - - - - - - - - - - - - - -
*/
/**
* perf_xmpl_test_server()
* run tests
*/
int perf_xmpl_test_server (wchar_t* uri, new_client_funcptr user_ctor, const int waitms)
{
const int runtime = 60, trials = 3, is_full = FALSE;
int i = 0, result = 0;
int threads[] = { 1, 2 };
/* threads[] = { 1, 2, 3, 4, 5, 6, 7, 8, 16, 32 }; */
const int numthreadcounts = sizeof(threads) / sizeof(int);
/* since this test presumably runs after the standard generated code in [main],
* display any memory leaks now before starting the test, such that leaks from
* the regular run can be isolated from any leaks occurring during this test,
* the latter shown with the normal cumulative leak display at etch shutdown.
*/
// check_etch_heap_bytes (TRUE, TRUE);
etchlog(ETCHTEST, ETCHLOG_INFO, "start perf server test for %d iterations\n",
numthreadcounts);
for(i = 0; i < numthreadcounts; i++)
{
const int numthreads = threads[i];
etchlog(ETCHTEST, ETCHLOG_INFO, "begin test iteration %d using %d threads ...\n",
i+1, numthreads);
#if(1)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf add test ...\n");
result = run_perftest ("add", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_add, user_ctor);
#endif
#if(0)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf sum test ...\n");
result = run_perftest ("sum", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_sum, user_ctor);
#endif
#if(0)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf report test ...\n");
result = run_perftest ("report", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_report, user_ctor);
#endif
#if(0)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf dist test ...\n");
result = run_perftest ("dist", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_dist, user_ctor);
#endif
#if(0)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf add2 test ...\n");
result = run_perftest ("add2", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_add2, user_ctor);
#endif
#if(0)
etchlog (ETCHTEST, ETCHLOG_INFO, "run perf report2 test ...\n");
result = run_perftest ("report2", uri, waitms, runtime, trials, numthreads,
perftest_threadproc_report2, user_ctor);
#endif
}
etchlog (ETCHTEST, ETCHLOG_INFO, "end perf server test\n");
return 0;
}