You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC
svn commit: r767594 [41/43] - in /incubator/etch/trunk/binding-c/runtime/c:
./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/
project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/
project/test/ project/test/logcli/...
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_client_tests.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_client_tests.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_client_tests.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_client_tests.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,1410 @@
+/* $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(¬ifyinfo, 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 (¬ifyinfo, 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;
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,446 @@
+/* $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_helper.c
+ * transport helper for perf service
+ */
+
+#include "etch_apr.h"
+#include "xmpl_perf_helper.h"
+#include "xmpl_perf_valufact.h"
+#include "xmpl_perf_client_impl.h"
+#include "etch_svcobj_masks.h"
+#include "etch_global.h"
+#include "etch_url.h"
+#include "etchlog.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+char* ETCHETCH = "ETCH";
+char* ETCHTHIS = "PERF";
+char* ETCHCVER = "etch C v0.5.000";
+
+
+/**
+ * new_remote_server()
+ * this is java binding's helper.newServer(uri, rex, implfactory);
+ * constructs a client side remote server per specs in the supplied uri.
+ * generally invoked from a run thread in the client main .exe.
+ * RemotePerfServer server = PerfHelper.newServer( uri, null, implFactory );
+ * @param uri
+ * @param p client parameters including callback to client ctor,
+ * caller reliquishes this memory.
+ * @return the new remote server object.
+ */
+perf_remote_server* new_remote_server (wchar_t* uri, etch_client_factory* p)
+{
+ i_perf_client* myclient = NULL;
+ perf_client_stub* client_stub = NULL;
+ i_delivery_service* deliverysvc = NULL;
+ perf_remote_server* remote_server = NULL;
+
+ perf_value_factory* vf = new_perf_value_factory();
+ ETCH_ASSERT(vf && p);
+ p->in_valufact = (etch_value_factory*) vf;
+ p->in_resx = etch_transport_resources_init(p->in_resx);
+ ETCH_ASSERT(p->in_resx);
+ etch_resources_add (p->in_resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (objmask*) vf);
+
+ /* instantiate a delivery service */
+ deliverysvc = new_etch_transport (uri, (etch_factory_params*) p, NULL);
+ ETCH_ASSERT(is_etch_ideliverysvc(deliverysvc)); /* TODO exception not assert */
+ p->dsvc = deliverysvc;
+
+ /* instantiate the remote server */
+ remote_server = new_perf_remote_server (NULL, deliverysvc, (etch_value_factory*) vf);
+
+ ETCH_ASSERT(is_etch_remote_server(remote_server)); /* TODO return exception or return null */
+ p->server_id = remote_server->server_base->server_id;
+ p->server = remote_server;
+ remote_server->client_factory = p; /* assume ownership */
+
+ /* here we call back to the client constructor in [main]. the purpose of the
+ * callback is to isolate the editable xxxx_client_impl constructor from the
+ * private constructor pieces. the callback instantiates a client implenentation
+ * and returns an interface to it.
+ */
+ myclient = p->new_client? p->new_client (remote_server): NULL;
+
+ ETCH_ASSERT(is_etch_client_base(myclient)); /* TODO return exception or return null */
+ p->iclient = myclient;
+
+ p->fpool = (etch_threadpool*) etch_resources_get (p->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+ p->qpool = (etch_threadpool*) etch_resources_get (p->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+ ETCH_ASSERT(p->fpool && p->qpool);
+
+ /* construct stub */
+ client_stub = new_perf_client_stub (p);
+
+ ETCH_ASSERT(is_etch_client_stub(client_stub));
+ p->stub = client_stub;
+
+ return remote_server;
+}
+
+
+/**
+ * new_perf_listener()
+ * invoked from [main] to construct the session listener.
+ * this function is simply a proxy providing additional parameters
+ * to new_etch_listener, in order to simplify the call in [main].
+ * @param main_new_server_callback pointer to [main]'s new_xxx_server()
+ * @return i_sessionlistener interface to listener. note that the returned
+ * listener.thisx is the specific server object, e.g. etch_tcp_server.
+ */
+i_sessionlistener* new_perf_listener (wchar_t* uri, main_new_server_funcptr main_new_server)
+{
+ i_sessionlistener* listener = NULL;
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "instantiating main listener ...\n");
+
+ listener = new_etch_listener (uri, NULL, new_helper_accepted_server,
+ main_new_server, new_perf_resources);
+
+ if (listener)
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "main listener instantiated\n");
+ else
+ etchlog (ETCHTHIS, ETCHLOG_ERROR, "could not instantiate main listener\n");
+
+ return listener;
+}
+
+
+/**
+ * start_perf_client()
+ * start the remote server, blocking until it comes up or errors out.
+ * @param uri the etch-formatted URI.
+ * @param new_client a pointer to a callback in the main client module
+ * which constructs the client implementation object and returns an interface
+ * to it.
+ * @param waitupms how long to wait for a connection to server to complete.
+ * @return the remote server, or null indicating error.
+ * todo return exception in remote server rather than null.
+ */
+perf_remote_server* start_perf_client (wchar_t* uri,
+ new_client_funcptr new_client, const int waitupms)
+{
+ int result = 0;
+ perf_remote* remotebase = NULL;
+ perf_remote_server* remote = NULL;
+ etch_client_factory* impl_factory = NULL;
+ ETCH_ASSERT(new_client);
+ etchlog_open_client(); /* force logger to use client filename */
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "creating perf client ...\n");
+
+ impl_factory = new_client_factory (NULL, NULL, new_client);
+ ETCH_ASSERT(impl_factory);
+
+ /* instantiate a remote server, which invokes client constructor */
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "instantiating remote server ...\n");
+
+ remote = new_remote_server (uri, impl_factory);
+
+ ETCH_ASSERT(remote); /* todo exception rather than assert */
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG,"remote server instantiated\n");
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "perf client created\n");
+ remotebase = remote->remote_base;
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "starting perf client ...\n");
+
+ /* fyi call sequence here is as follows:
+ * etchremote_start_waitup()
+ * etchremote_transport_control()
+ * tcpdelsvc_transport_control()
+ * pmboxmgr_transport_control()
+ * msgzr_transport_control()
+ * pktzr_transport_control()
+ * tcpconx_transport_control()
+ * tcpconx_start()
+ * tcpconx_open()
+ */
+
+ /* BLOCK here until the connection to server comes up or times out */
+ result = remotebase->start_waitup (remotebase, waitupms);
+
+ if (0 != result)
+ { /* todo return exception with actual error in remote, rather than null */
+ etchlog (ETCHTHIS, ETCHLOG_ERROR, "could not start perf client\n");
+ remote->destroy(remote);
+ remote = NULL;
+ }
+ else etchlog (ETCHTHIS, ETCHLOG_INFO, "perf client started\n");
+
+ return remote;
+}
+
+
+/**
+ * stop_perf_client()
+ * stop the remote server, blocking until it comes down or errors out.
+ * @return 0 success, -1 failure
+ * TODO return exception rather than result code.
+ */
+int stop_perf_client (perf_remote_server* remote, const int waitdownms)
+{
+ int result = 0;
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "stopping perf client ...\n");
+
+ /* fyi call sequence here is as follows:
+ * etchremote_stop_waitdown()
+ * etchremote_transport_control()
+ * tcpdelsvc_transport_control()
+ * pmboxmgr_transport_control()
+ * msgizer_transport_control()
+ * pktizer_transport_control()
+ * tcpconx_transport_control()
+ * tcpclient_stop_listener()
+ * tcpconx_closex()
+ */
+ result = remote->remote_base->stop_waitdown (remote->remote_base, waitdownms);
+
+ if (0 == result)
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "perf client stopped\n");
+ else etchlog (ETCHTHIS, ETCHLOG_ERROR, "could not stop perf client\n");
+
+ return result;
+}
+
+
+/**
+ * run_perf_listener()
+ * start the main (accept) listener, block until listener exit,
+ * and finally tear down this server's outstanding client sessions.
+ * @return 0 success, -1 failure.
+ */
+int run_perf_listener (i_sessionlistener* listener, const int waitupms)
+{
+ int result = 0;
+ if (NULL == listener) return -1;
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "starting main listener ...\n");
+
+ /* call through to e.g. etch_tcpsvr_transport_control() to start listener */
+ result = listener->transport_control (listener->thisx,
+ new_etch_event(CLASSID_CONTROL_START_WAITUP, waitupms), NULL);
+
+ if (0 == result)
+ { etchlog (ETCHTHIS, ETCHLOG_INFO, "main listener started on thread %d\n",
+ transport_thread_id (listener));
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "listening for connect requests ...\n");
+
+ /* BLOCK here until listener thread exits (etch_listener_waitfor_exit) */
+ result = listener->wait_exit (listener);
+
+ etchlog (ETCHTHIS, ETCHLOG_INFO, "main listener ended\n");
+
+ if (transport_session_count (listener) > 0)
+ {
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "begin client sessions teardown\n");
+
+ result = transport_teardown_client_sessions (listener);
+
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "end client sessions teardown\n");
+ }
+ }
+ else
+ etchlog (ETCHTHIS, ETCHLOG_ERROR, "could not start main listener\n");
+
+ return result;
+}
+
+
+/**
+ * new_perf_resources()
+ * callback from new_etch_listener to initialize service-specific resources.
+ * @param p the etch_server_factory to be initialized
+ * @return 0 success, -1 failure.
+ */
+int new_perf_resources (etch_server_factory* p)
+{
+ int result = 0;
+ ETCH_ASSERT((NULL != p) && (NULL == p->in_valufact));
+ ETCH_ASSERT (p->in_resx && is_etch_hashtable(p->in_resx));
+
+ p->in_valufact = (etch_value_factory*) new_perf_value_factory ();
+ ETCH_ASSERT(p->in_valufact);
+ if (NULL == p->in_valufact) return -1;
+
+ result = etch_resources_add (p->in_resx,
+ ETCH_RESXKEY_MSGIZER_VALUFACT, (objmask*) p->in_valufact);
+
+ ETCH_ASSERT(0 == result);
+ return result;
+}
+
+
+/**
+ * new_helper_accepted_server()
+ * this is java binding's newServer().
+ * constructs the server side listener component of a remote client.
+ * invoked from the server's accepted connection handler, such as
+ * tcpxfact_session_accepted(), to create the remote client and stub
+ * with which to communicate with the individual client.
+ * we see then that each client has its own listener thread on the server,
+ * as opposed to a client ID scheme where all clients would filter through
+ * a single socket on the server.
+ * @param p parameter bundle, including the callback to the to the service-
+ * specific new server constructors in [main]. caller relinquishes.
+ * @return the client's service-specific server stub.
+ */
+void* new_helper_accepted_server (etch_server_factory* p, etch_session* session)
+{
+ i_perf_server* iserver;
+ perf_server_stub* stub;
+ perf_remote_client* client;
+ ETCH_ASSERT(p && p->helper_new_accepted && p->main_new_server);
+ ETCH_ASSERT(p->in_resx && p->in_valufact); // TODO assert delivery service
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "instantiating accepted client listener ...\n");
+
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "creating remote client...\n");
+ client = new_remote_client (NULL, session, p->in_valufact);
+ client->session_id = session->session_id;
+ session->client = client;
+
+ /* here we CALL BACK to the constructor in [main], the purpose of the callback
+ * being to isolate the editable constructor from the private constructor.
+ * the callback instantiates a client's server implementation and returns
+ * an interface to it.
+ */
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "creating server implementation ...\n");
+ iserver = p->main_new_server (p, session);
+ iserver->session_id = session->session_id;
+ session->server = iserver;
+
+ /* note that the main listener will use p->mainpool as a thread manager, not these */
+ p->qpool = (etch_threadpool*) etch_resources_get(p->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+ p->fpool = (etch_threadpool*) etch_resources_get(p->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+
+ /* eventually new_perf_server_stub() gets to stub_base constructor, which sets
+ * the delivery service's session to this, the server stub. so, in the java binding,
+ * the server stub is referenced as delivery service.session. we should perhaps also
+ * store the stub opaquely in both the client and listener objects.
+ */
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "creating server stub ...\n");
+ stub = new_perf_server_stub (p, session);
+ stub->session_id = session->session_id;
+ session->server_stub = stub;
+
+ if (iserver && stub)
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "accepted client listener instantiated\n");
+ else
+ etchlog (ETCHTHIS, ETCHLOG_ERROR, "could not instantiate accepted client listener\n");
+
+ return stub;
+}
+
+
+/**
+ * get_perf_client_impl()
+ * convenience to extract the client impl from the remote server object.
+ */
+perf_client_impl* get_perf_client_impl (perf_remote_server* rs)
+{
+ i_perf_client* iclient = rs->client_factory->iclient;
+ perf_client_impl* pci = iclient? iclient->thisx: NULL;
+ return pci;
+}
+
+
+/**
+ * get_perf_client_stub()
+ * convenience to extract the client stub from the remote server object.
+ */
+perf_client_stub* get_perf_client_stub (perf_remote_server* rs)
+{
+ perf_client_stub* stub = (perf_client_stub*) rs->client_factory->stub;
+ ETCH_ASSERT(is_perf_client_stub(stub));
+ return stub;
+}
+
+
+/**
+ * get_perf_client_stubbase()
+ * convenience to extract the client stub base from the remote server object.
+ */
+etch_stub* get_perf_client_stubbase (perf_remote_server* rs)
+{
+ perf_client_stub* stub = get_perf_client_stub (rs);
+ etch_stub* base = stub->stub_base;
+ ETCH_ASSERT(is_etch_stub(base));
+ return base;
+}
+
+
+/**
+ * perf_client_cleanup()
+ * destroy instantiations from [main]
+ */
+void perf_client_cleanup (perf_remote_server* remote)
+{
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "destroying remote server ...\n");
+ ETCHOBJ_DESTROY(remote);
+ etchlog (ETCHTHIS, ETCHLOG_DEBUG, "remote server destroyed\n");
+}
+
+
+/**
+ * etch_init()
+ * do client-side etch runtime initialization and service-specific initialization.
+ * this is intended as a convenience function to be invoked only by user client code.
+ */
+int etch_init()
+{
+ return perf_runtime_init(INIT_ETCH_CLIENT);
+}
+
+
+/**
+ * etch_exit()
+ * etch runtime teardown plus service-specific teardown
+ * this is intended as a convenience function to be invoked only by user client code.
+ */
+int etch_exit()
+{
+ return perf_runtime_exit();
+}
+
+
+/**
+ * perf_runtime_exit()
+ * do etch runtime teardown plus service-specific teardown.
+ */
+int perf_runtime_exit ()
+{
+ etchvf_free_builtins(); /* TODO move this somewhere else */
+ exitparams.is_show_leak_detail = config.is_log_memory_leak_detail;
+ etch_runtime_exit (&exitparams);
+ printf("\n%s exit\n", ETCHCVER);
+ return 0;
+}
+
+
+/**
+ * perf_runtime_init()
+ * do etch runtime initialization plus service-specific initialization.
+ */
+int perf_runtime_init (const int is_client)
+{
+ printf("%s %s start\n", ETCHCVER, is_client? "client": "server");
+
+ return etch_runtime_init_all (is_client);
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.h
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.h?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.h (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_helper.h Wed Apr 22 17:25:43 2009
@@ -0,0 +1,63 @@
+/* $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_helper.h
+ * transport helper for perf service
+ */
+#ifndef PERF_HELPER_H
+#define PERF_HELPER_H
+
+#include "etch_apr.h"
+#include "etch_transport.h"
+#include "etch_stub.h"
+#include "xmpl_perf_client.h"
+#include "xmpl_perf_server.h"
+#include "xmpl_perf_client_stub.h"
+#include "xmpl_perf_server_stub.h"
+#include "xmpl_perf_remote_server.h"
+#include "xmpl_perf_remote_client.h"
+etch_runtime_exit_params exitparams;
+
+void perf_client_cleanup (perf_remote_server*);
+int perf_runtime_init (const int is_client);
+int perf_runtime_exit ();
+
+int new_perf_resources (etch_server_factory*);
+
+/* indicate if compiling an etch example as opposed to a regular etch client */
+#define IS_ETCH_EXAMPLE TRUE
+
+/* client side user calls */
+int etch_init();
+int etch_exit();
+perf_remote_server* new_remote_server (wchar_t* uri, etch_client_factory*);
+perf_remote_server* start_perf_client (wchar_t* uri, new_client_funcptr, const int waitms);
+perf_client_impl* get_perf_client_impl (perf_remote_server*);
+perf_client_stub* get_perf_client_stub (perf_remote_server*);
+etch_stub* get_perf_client_stubbase (perf_remote_server*);
+int stop_perf_client (perf_remote_server*, const int waitdownms);
+
+/* server side */
+void* new_helper_accepted_server (etch_server_factory*, etch_session*);
+i_sessionlistener* new_perf_listener (wchar_t* uri, main_new_server_funcptr);
+int run_perf_listener (i_sessionlistener*, const int waitupms);
+
+
+#endif /* PERF_HELPER_H */
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,66 @@
+/* $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_listener_main.c
+ * establishes client session listeners on the server.
+ */
+#include "xmpl_perf_listener_main.h"
+
+
+/**
+ * main()
+ * reference MainPerfListener.java. see serverexe.txt for callback map.
+ */
+int _tmain(int argc, _TCHAR* argv[])
+{
+ int result = -1, is_waitkey = TRUE, waitupms = 4000;
+ wchar_t* uri = argc > 1? argv[1]: L"tcp://127.0.0.1:4004";
+
+ if (0 == perf_runtime_init(INIT_ETCH_SERVER))
+ {
+ i_sessionlistener* listener = new_perf_listener (uri, new_perf_server);
+
+ result = run_perf_listener (listener, waitupms); /* start server and block */
+
+ /* at this point all connections are down and destroyed */
+ ETCHOBJ_DESTROY(listener); /* destroy_etch_listener() */
+ }
+
+ perf_runtime_exit ();
+ return waitkey (is_waitkey, result);
+}
+
+
+/**
+ * new_perf_server()
+ * create an individual client's perf server implementation.
+ * this is java binding's newPerfServer().
+ * this is called back from helper.new_helper_accepted_server() (java's newServer).
+ * @param p parameter bundle. caller retains.
+ * @return the i_perf_server, whose thisx is the perf_server_impl.
+ */
+i_perf_server* new_perf_server (etch_server_factory* p, etch_session* session)
+{
+ perf_remote_client* client = (perf_remote_client*) session->client;
+
+ perf_server_impl* newserver = new_perf_server_impl (client);
+
+ return newserver->perf_server_base;
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.h
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.h?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.h (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_listener_main.h Wed Apr 22 17:25:43 2009
@@ -0,0 +1,57 @@
+/* $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_listener_main.h
+ * server exe main() private header
+ */
+
+#ifndef ETCH_SERVERMAIN_H
+#define ETCH_SERVERMAIN_H
+
+#include "etch_apr.h"
+#include "etch_url.h"
+#include "etchthread.h"
+#include "etch_global.h"
+#include "xmpl_perf_helper.h"
+#include "xmpl_perf_server_impl.h"
+#include "xmpl_perf_remote_client.h"
+#include <tchar.h>
+#include <stdio.h>
+
+#if(0)
+
+ IMPL_XXXX_SERVER
+ | RemotePerfClient* client;
+ | myfoo() { } etc; { /* service method implementations */ }
+ | mydata;
+ - BASE_XXXX_SERVER
+ | myfoo(); mybar(); etc. /* service method empty stubs */
+ |- XXXX_SERVER: XXXX (interfaces)
+ |- myfoo(); mybar(); etc. /* service method interfaces */
+ | mydata;
+ - OBJSESSION
+ | _sessionControl(), _sessionNotify(), _sessionQuery()
+#endif
+
+
+i_perf_server* new_perf_server (etch_server_factory*, etch_session*);
+
+
+#endif /* ETCH_SERVERMAIN_H */
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,269 @@
+/* $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_remote.c
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "xmpl_perf_remote.h"
+#include "etch_global.h"
+#include "etch_url.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+
+int destroy_perf_remote (perf_remote*);
+#if(0)
+etch_message* etchremote_new_message(perf_remote*, etch_type*);
+int etchremote_send(perf_remote*, etch_message*);
+int etchremote_begincall(perf_remote*, etch_message*, void**);
+int etchremote_endcall (perf_remote*, i_mailbox*, etch_type*, void**);
+int etchremote_transport_control (perf_remote*, etch_event*, etch_int32*);
+int etchremote_transport_notify (perf_remote*, etch_event*);
+objmask* etchremote_transport_query (perf_remote*, objmask*);
+int etchremote_start_waitup (perf_remote*, const int);
+int etchremote_stop_waitdown (perf_remote*, const int);
+#endif
+
+
+/* - - - - - - - - - - - - - -
+ * constructors
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_perf_remote
+ * @param ids delivery service -- caller retains
+ * @param vf perf value factory - caller retains
+ * @param iperf optional perf service interface -- caller retains
+ */
+perf_remote* new_perf_remote (void* thisx,
+ i_delivery_service* ids, etch_value_factory* vf, i_perf* iservice)
+{
+ perf_remote* remote = (perf_remote*) new_object (sizeof(perf_remote),
+ ETCHTYPEB_REMOTE, get_dynamic_classid_unique(&CLASSID_REMOTE_PERF));
+
+ remote->destroy = destroy_perf_remote;
+
+ /* perf_remote instance data and methods */
+ remote->dsvc = ids;
+ remote->vf = vf;
+ remote->start_waitup = etchremote_start_waitup;
+ remote->stop_waitdown = etchremote_stop_waitdown;
+
+ /* transport methods */
+ remote->transport_control = etchremote_transport_control;
+ remote->transport_notify = etchremote_transport_notify;
+ remote->transport_query = etchremote_transport_query;
+
+ /* remote base */
+ remote->new_message = etchremote_new_message;
+ remote->send = etchremote_send;
+ remote->sendex = etchremote_sendex;
+ remote->begin_call = etchremote_begincall;
+ remote->end_call = etchremote_endcall;
+
+ /* perf service */
+ if (iservice)
+ remote->iperf = iservice;
+ else
+ { remote->iperf = new_perf_service_interface();
+ remote->is_service_interface_owned = TRUE;
+ }
+ remote->add = remote->iperf->add;
+ remote->sum = remote->iperf->sum;
+ remote->report = remote->iperf->report;
+ remote->dist = remote->iperf->dist;
+ remote->add2 = remote->iperf->add2;
+ remote->report2= remote->iperf->report2;
+ remote->point = remote->iperf->point;
+
+ return remote;
+}
+
+
+/**
+ * destroy_perf_remote()
+ * perf_remote destructor.
+ */
+int destroy_perf_remote (perf_remote* thisx)
+{
+ if (NULL == thisx) return -1;
+ if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;
+
+ if (!is_etchobj_static_content(thisx))
+ {
+ if (thisx->is_service_interface_owned && thisx->iperf)
+ thisx->iperf->destroy(thisx->iperf);
+ }
+
+ return destroy_objectex((objmask*)thisx);
+}
+
+
+/* - - - - - - - - - - - - - -
+ * remote methods
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, which could wrap an exception.
+ */
+#if(0)
+etch_message* etchremote_new_message (perf_remote* thisx, etch_type* message_type)
+{
+ etch_message* msg = new_message(message_type, ETCH_DEFSIZE, thisx->vf);
+ return msg;
+}
+#endif
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_send (perf_remote* thisx, etch_message* msg)
+{
+ const int result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_begincall (perf_remote* thisx, etch_message* msg, i_mailbox** out)
+{
+ const int result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_endcall (perf_remote* thisx, i_mailbox* mbox, etch_type* response_type, objmask** out)
+{
+ const int result = thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_transport_control (perf_remote* thisx, etch_event* evt, etch_int32* value)
+{
+ const int result = thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_transport_notify (perf_remote* thisx, etch_event* evt)
+{
+ const int result = thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+objmask* etchremote_transport_query (perf_remote* thisx, objmask* query)
+{
+ objmask* resultobj = thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+ return resultobj;
+}
+#endif
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_start_waitup (perf_remote* thisx, const int waitms)
+{
+ const int result = thisx->transport_control(thisx,
+ new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms), NULL);
+
+ return result;
+}
+#endif
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_stop_waitdown (perf_remote* thisx, const int waitms)
+{
+ const int result = thisx->transport_control(thisx,
+ new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms), NULL);
+
+ return result;
+}
+#endif
Added: incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.h
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.h?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.h (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/xamples/perf/xmpl_perf_remote.h Wed Apr 22 17:25:43 2009
@@ -0,0 +1,105 @@
+/* $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_remote.h
+ * perf remote.
+ * combines java bindings's RemotePerf, Perf, and RemoteBase.
+ */
+
+#ifndef PERF_REMOTE_H
+#define PERF_REMOTE_H
+
+#include "xmpl_perf.h"
+#include "etch_remote.h"
+#include "etch_transport.h"
+unsigned short CLASSID_REMOTE_PERF;
+
+
+/**
+ * perf_remote
+ */
+typedef struct perf_remote
+{
+ unsigned int hashkey;
+ unsigned short obj_type;
+ unsigned short class_id;
+ struct objmask* vtab;
+ int (*destroy)(void*);
+ void*(*clone) (void*);
+ obj_gethashkey get_hashkey;
+ struct objmask* parent;
+ etchresult* result;
+ unsigned int refcount;
+ unsigned int length;
+ unsigned char is_null;
+ unsigned char is_copy;
+ unsigned char is_static;
+ unsigned char reserved;
+
+ i_perf* iperf; /* possibly owned */
+ i_delivery_service* dsvc; /* not owned */
+ etch_value_factory* vf; /* not owned */
+ unsigned char remote_type; /* client or server */
+ unsigned char is_service_interface_owned;
+ unsigned short unused; /* alignment */
+
+ etch_message* (*new_message) (void*, etch_type*);
+ int (*send) (void*, etch_message*);
+ void* (*sendex) (void*, etch_message*);
+ etch_delivsvc_begincall begin_call; /* i_mailbox** out */
+ etch_delvisvc_endcall end_call; /* objmask** out */
+
+ int (*start_waitup) (void*, const int waitms);
+ int (*stop_waitdown) (void*, const int waitms);
+
+ /* - - - - - - - - - - - - -
+ * transport functionality
+ * - - - - - - - - - - - - -
+ */
+ etch_transport_control transport_control;
+ etch_transport_notify transport_notify;
+ etch_transport_query transport_query;
+ etch_transport_get_session get_session;
+ etch_transport_set_session set_session;
+
+ /* - - - - - - - - - - -
+ * service virtuals
+ * - - - - - - - - - - -
+ */
+ perf_add add;
+ perf_sum sum;
+ perf_report report;
+ perf_dist dist;
+ perf_add2 add2;
+ perf_report2 report2;
+ perf_point* point;
+
+ /* - - - - - - - - - - -
+ * private instance data
+ * - - - - - - - - - - -
+ */
+
+} perf_remote;
+
+
+perf_remote* new_perf_remote (void*, i_delivery_service*, etch_value_factory*, i_perf*);
+
+
+#endif /* PERF_REMOTE_H */
+