Files
pcas/src/ca/catime.c
2009-07-31 23:26:16 +00:00

686 lines
17 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 NULL
#define NULL 0
#endif
#define WAIT_FOR_ACK
typedef struct testItem {
chid chix;
char name[128];
int type;
int count;
void * pValue;
} ti;
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
/*
* test_pend()
*/
static 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 ()
*/
static 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
static 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 ()
*/
static 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 ()
*/
static 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->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
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].pValue);
SEVCHK (status, NULL);
status = ca_flush_io();
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_get ()
*/
static 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->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
}
status = ca_pend_io(1e20);
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_wait ()
*/
static 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->pValue);
SEVCHK (status, NULL);
status = ca_pend_io(100.0);
SEVCHK (status, NULL);
}
*pInlineIter = 1;
}
/*
* measure_get_latency
*/
static 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->pValue );
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 (
"Get Latency - "
"mean = %3.1f uS, "
"std dev = %3.1f uS, "
"min = %3.1f uS "
"max = %3.1f uS\n",
mean * 1e6, stdDev * 1e6,
min * 1e6, max * 1e6 );
}
/*
* printSearchStat()
*/
static 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 = %3.1f "
"std dev = %3.1f "
"min = %3.1f "
"max = %3.1f\n",
mean, stdDev, min, max);
}
/*
* timeIt ()
*/
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
unsigned nBytesSent, unsigned nBytesRecv )
{
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 ( "Per Op, %8.4f uS ( %8.4f MHz )",
1e6 / freq, freq / 1e6 );
if ( pItems != NULL ) {
printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
(inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
(inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
}
else {
printf ("\n");
}
}
}
/*
* test ()
*/
static void test ( ti *pItems, unsigned iterations )
{
unsigned payloadSize, dblPayloadSize;
unsigned nBytesSent, nBytesRecv;
payloadSize =
dbr_size_n ( pItems[0].type, pItems[0].count );
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
dblPayloadSize = dbr_size [ DBR_DOUBLE ];
dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
if ( payloadSize > dblPayloadSize ) {
unsigned factor = payloadSize / dblPayloadSize;
while ( factor ) {
if ( iterations > 10 * factor ) {
iterations /= factor;
break;
}
factor /= 2;
}
}
printf ( "\t### async put test ###\n");
nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
nBytesRecv = 0u;
timeIt ( test_put, pItems, iterations,
nBytesSent * iterations,
nBytesRecv * iterations );
printf ( "\t### async get test ###\n");
nBytesSent = sizeof ( caHdr );
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
timeIt ( test_get, pItems, iterations,
nBytesSent * ( iterations ),
nBytesRecv * ( iterations ) );
printf ("\t### synch get test ###\n");
nBytesSent = sizeof ( caHdr );
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
if ( iterations > 100 ) {
iterations /= 100;
}
else if ( iterations > 10 ) {
iterations /= 10;
}
timeIt ( test_wait, pItems, iterations,
nBytesSent * iterations,
nBytesRecv * iterations );
}
/*
* catime ()
*/
int catime ( const char * channelName,
unsigned channelCount, enum appendNumberFlag appNF )
{
unsigned i;
int j;
unsigned strsize;
unsigned nBytesSent, nBytesRecv;
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;
nBytesSent = 0;
nBytesRecv = 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 = 0;
pItemList[i].pValue = 0;
nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
+ sizeof (caHdr) );
nBytesRecv += 2 * sizeof (caHdr);
}
printf ( "Channel Connect Test\n" );
printf ( "--------------------\n" );
timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
printSearchStat ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
size_t count = ca_element_count ( pItemList[i].chix );
size_t size = sizeof ( dbr_string_t ) * count;
pItemList[i].count = count;
pItemList[i].pValue = malloc ( size );
assert ( pItemList[i].pValue );
}
printf (
"channel name=%s, native type=%d, native count=%u\n",
ca_name (pItemList[0].chix),
ca_field_type (pItemList[0].chix),
pItemList[0].count );
printf ("Pend Event Test\n");
printf ( "----------------\n" );
timeIt ( test_pend, NULL, 100, 0, 0 );
for ( i = 0; i < channelCount; i++ ) {
dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pFltVal[j] = (dbr_float_t) val;
}
pItemList[i].type = DBR_FLOAT;
}
printf ( "DBR_FLOAT Test\n" );
printf ( "--------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pDblVal[j] = (dbr_double_t) val;
}
pItemList[i].type = DBR_DOUBLE;
}
printf ( "DBR_DOUBLE Test\n" );
printf ( "---------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
sprintf ( pStrVal[j], "%f", val );
}
pItemList[i].type = DBR_STRING;
}
printf ( "DBR_STRING Test\n" );
printf ( "---------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pIntVal[j] = (dbr_int_t) val;
}
pItemList[i].type = DBR_INT;
}
printf ( "DBR_INT Test\n" );
printf ( "------------\n" );
test ( pItemList, channelCount );
printf ( "Get Latency Test\n" );
printf ( "----------------\n" );
for ( i = 0; i < channelCount; i++ ) {
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
for ( j = 0; j < pItemList[i].count; j++ ) {
pDblVal[j] = 0;
}
pItemList[i].type = DBR_DOUBLE;
}
measure_get_latency ( pItemList, channelCount );
printf ( "Free Channel Test\n" );
printf ( "-----------------\n" );
timeIt ( test_free, pItemList, channelCount, 0, 0 );
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
for ( i = 0; i < channelCount; i++ ) {
free ( pItemList[i].pValue );
}
free ( pItemList );
return CATIME_OK;
}