Files
epics-base/src/ca/catime.c
2004-10-04 18:39:03 +00:00

603 lines
14 KiB
C

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* CA performance test
*
* History
* joh 09-12-89 Initial release
* joh 12-20-94 portability
*
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "epicsAssert.h"
#include "epicsTime.h"
#include "cadef.h"
#include "caProto.h"
#include "caDiagnostics.h"
#ifndef LOCAL
#define LOCAL static
#endif
#ifndef NULL
#define NULL 0
#endif
#define WAIT_FOR_ACK
typedef struct testItem {
chid chix;
char name[40];
int type;
int count;
union {
dbr_double_t doubleval;
dbr_float_t fltval;
dbr_short_t intval;
dbr_string_t strval;
} val;
} ti;
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
/*
* test_pend()
*/
LOCAL void test_pend(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for (i=0; i<iterations; i++) {
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
}
*pInlineIter = 5;
}
/*
* test_search ()
*/
LOCAL void test_search (
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for ( i = 0u; i < iterations; i++ ) {
status = ca_search ( pItems[i].name, &pItems[i].chix );
SEVCHK (status, NULL);
}
status = ca_pend_io ( 0.0 );
SEVCHK ( status, NULL );
*pInlineIter = 1;
}
/*
* test_sync_search()
*/
#if 0
LOCAL void test_sync_search(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for (i=0u; i<iterations; i++) {
status = ca_search (pItems[i].name, &pItems[i].chix);
SEVCHK (status, NULL);
status = ca_pend_io(0.0);
SEVCHK (status, NULL);
}
*pInlineIter = 1;
}
#endif
/*
* test_free ()
*/
LOCAL void test_free(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
int status;
unsigned i;
for (i=0u; i<iterations; i++) {
status = ca_clear_channel (pItems[i].chix);
SEVCHK (status, NULL);
}
status = ca_flush_io();
SEVCHK (status, NULL);
*pInlineIter = 1;
}
/*
* test_put ()
*/
LOCAL void test_put(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
dbr_int_t val;
for (pi=pItems; pi<&pItems[iterations]; pi++) {
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
}
#ifdef WAIT_FOR_ACK
status = ca_array_get (DBR_INT, 1, pItems[0].chix, &val);
SEVCHK (status, NULL);
ca_pend_io(100.0);
#endif
status = ca_array_put(
pItems[0].type,
pItems[0].count,
pItems[0].chix,
&pItems[0].val);
SEVCHK (status, NULL);
status = ca_flush_io();
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_get ()
*/
LOCAL void test_get(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
for (pi=pItems; pi<&pItems[iterations]; pi++) {
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
}
status = ca_pend_io(100.0);
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_wait ()
*/
LOCAL void test_wait (
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
for (pi=pItems; pi<&pItems[iterations]; pi++) {
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
&pi->val);
SEVCHK (status, NULL);
status = ca_pend_io(100.0);
SEVCHK (status, NULL);
}
*pInlineIter = 1;
}
/*
* measure_get_latency
*/
LOCAL void measure_get_latency (ti *pItems, unsigned iterations)
{
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
double X = 0u;
double XX = 0u;
double max = DBL_MIN;
double min = DBL_MAX;
double mean;
double stdDev;
ti *pi;
int status;
for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
epicsTimeGetCurrent ( &start_time );
status = ca_array_get ( pi->type, pi->count,
pi->chix, &pi->val );
SEVCHK ( status, NULL );
status = ca_pend_io ( 100.0 );
SEVCHK ( status, NULL );
epicsTimeGetCurrent ( &end_time );
delay = epicsTimeDiffInSeconds ( &end_time,&start_time );
X += delay;
XX += delay*delay;
if ( delay > max ) {
max = delay;
}
if ( delay < min ) {
min = delay;
}
}
mean = X/iterations;
stdDev = sqrt ( XX/iterations - mean*mean );
printf ( "Round trip get delays - mean=%f sec, std dev=%f sec, min=%f sec max=%f sec\n",
mean, stdDev, min, max );
}
/*
* printSearchStat()
*/
LOCAL void printSearchStat ( const ti *pi, unsigned iterations )
{
unsigned i;
double X = 0u;
double XX = 0u;
double max = DBL_MIN;
double min = DBL_MAX;
double mean;
double stdDev;
for ( i = 0; i < iterations; i++ ) {
double retry = ca_search_attempts ( pi[i].chix );
X += retry;
XX += retry * retry;
if ( retry > max ) {
max = retry;
}
if ( retry < min ) {
min = retry;
}
}
mean = X / iterations;
stdDev = sqrt( XX / iterations - mean * mean );
printf ( "Search tries per chan - mean=%f std dev=%f min=%f max=%f\n",
mean, stdDev, min, max);
}
/*
* timeIt ()
*/
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations, unsigned nBytes )
{
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
unsigned inlineIter;
epicsTimeGetCurrent (&start_time);
(*pfunc) (pItems, iterations, &inlineIter);
epicsTimeGetCurrent (&end_time);
delay = epicsTimeDiffInSeconds (&end_time, &start_time);
if (delay>0.0) {
double freq = ( iterations * inlineIter ) / delay;
printf ( "Elapsed Per Item = %12.8f sec, %10.1f Items per sec",
1.0 / freq, freq );
if ( pItems != NULL ) {
printf(", %3.1f Mbps\n",
(inlineIter*nBytes*CHAR_BIT)/(delay*1e6));
}
else {
printf ("\n");
}
}
else {
printf ("Elapsed Per Item = %12.8f sec\n",
delay/(iterations*inlineIter));
}
}
/*
* test ()
*/
LOCAL void test ( ti *pItems, unsigned iterations )
{
unsigned nBytes;
printf ( "\tasync put test\n");
nBytes = sizeof ( caHdr ) + OCT_ROUND( dbr_size[pItems[0].type] );
timeIt ( test_put, pItems, iterations, nBytes * iterations );
printf ( "\tasync get test\n");
nBytes = 2 * sizeof ( caHdr ) + OCT_ROUND ( dbr_size[pItems[0].type] );
timeIt ( test_get, pItems, iterations/2, nBytes * ( iterations / 2 ) );
printf ("\tsynch get test\n");
nBytes = 2 * sizeof ( caHdr ) + OCT_ROUND ( dbr_size[pItems[0].type] );
timeIt ( test_wait, pItems, iterations/100, nBytes * ( iterations / 100 ) );
}
/*
* catime ()
*/
int catime ( const char * channelName,
unsigned channelCount, enum appendNumberFlag appNF )
{
unsigned i;
unsigned strsize;
unsigned nBytes;
ti *pItemList;
if ( channelCount == 0 ) {
printf ( "channel count was zero\n" );
return 0;
}
pItemList = calloc ( channelCount, sizeof (ti) );
if ( ! pItemList ) {
return -1;
}
SEVCHK ( ca_context_create ( ca_disable_preemptive_callback ),
"Unable to initialize" );
if ( appNF == appendNumber ) {
printf ( "Testing with %u channels named %snnn\n",
channelCount, channelName );
}
else {
printf ( "Testing with %u channels named %s\n",
channelCount, channelName );
}
strsize = sizeof ( pItemList[0].name ) - 1;
nBytes = 0;
for ( i=0; i < channelCount; i++ ) {
if ( appNF == appendNumber ) {
sprintf ( pItemList[i].name,"%.*s%.6u",
(int) (strsize - 15u), channelName, i );
}
else {
strncpy ( pItemList[i].name, channelName, strsize);
}
pItemList[i].name[strsize]= '\0';
pItemList[i].count = 1;
nBytes += 2 * ( OCT_ROUND ( strlen ( pItemList[i].name ) ) + 2 * sizeof (caHdr) );
}
printf ( "channel connect test\n" );
timeIt ( test_search, pItemList, channelCount, nBytes );
printSearchStat ( pItemList, channelCount );
printf (
"channel name=%s, native type=%d, native count=%lu\n",
ca_name (pItemList[0].chix),
ca_field_type (pItemList[0].chix),
ca_element_count (pItemList[0].chix));
printf ("\tpend event test\n");
timeIt (test_pend, NULL, 100, 0);
for ( i = 0; i < channelCount; i++ ) {
pItemList[i].val.fltval = 0.0f;
pItemList[i].type = DBR_FLOAT;
}
printf ( "float test\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
pItemList[i].val.doubleval = 0.0;
pItemList[i].type = DBR_DOUBLE;
}
printf ( "double test\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
strcpy ( pItemList[i].val.strval, "0.0" );
pItemList[i].type = DBR_STRING;
}
printf ( "string test\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
pItemList[i].val.intval = 0;
pItemList[i].type = DBR_INT;
}
printf ( "integer test\n" );
test ( pItemList, channelCount );
printf ( "round trip jitter test\n" );
for ( i = 0; i < channelCount; i++ ) {
pItemList[i].val.fltval = 0.0f;
pItemList[i].type = DBR_DOUBLE;
}
measure_get_latency ( pItemList, channelCount );
printf ("free test\n");
timeIt ( test_free, pItemList, channelCount, 0 );
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
free ( pItemList );
return CATIME_OK;
}