This is Unofficial EPICS BASE Doxygen Site
catime.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE Versions 3.13.7
7 * and higher are distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /*
11  *
12  * CA performance test
13  *
14  * History
15  * joh 09-12-89 Initial release
16  * joh 12-20-94 portability
17  *
18  *
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include <limits.h>
27 
28 #define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
29 
30 #include "epicsAssert.h"
31 #include "epicsTime.h"
32 #include "cadef.h"
33 #include "caProto.h"
34 
35 #include "caDiagnostics.h"
36 
37 #ifndef NULL
38 #define NULL 0
39 #endif
40 
41 #define WAIT_FOR_ACK
42 
43 typedef struct testItem {
45  char name[128];
46  int type;
47  int count;
48  void * pValue;
49 } ti;
50 
51 typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
52 
53 /*
54  * test_pend()
55  */
56 static void test_pend(
57 ti *pItems,
58 unsigned iterations,
59 unsigned *pInlineIter
60 )
61 {
62  unsigned i;
63  int status;
64 
65  for (i=0; i<iterations; i++) {
66  status = ca_pend_event(1e-9);
67  if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
68  SEVCHK(status, NULL);
69  }
70  status = ca_pend_event(1e-9);
71  if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
72  SEVCHK(status, NULL);
73  }
74  status = ca_pend_event(1e-9);
75  if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
76  SEVCHK(status, NULL);
77  }
78  status = ca_pend_event(1e-9);
79  if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
80  SEVCHK(status, NULL);
81  }
82  status = ca_pend_event(1e-9);
83  if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
84  SEVCHK(status, NULL);
85  }
86  }
87  *pInlineIter = 5;
88 }
89 
90 /*
91  * test_search ()
92  */
93 static void test_search (
94 ti *pItems,
95 unsigned iterations,
96 unsigned *pInlineIter
97 )
98 {
99  unsigned i;
100  int status;
101 
102  for ( i = 0u; i < iterations; i++ ) {
103  status = ca_search ( pItems[i].name, &pItems[i].chix );
104  SEVCHK (status, NULL);
105  }
106  status = ca_pend_io ( 0.0 );
107  SEVCHK ( status, NULL );
108 
109  *pInlineIter = 1;
110 }
111 
112 /*
113  * test_sync_search()
114  */
115 #if 0
116 static void test_sync_search(
117 ti *pItems,
118 unsigned iterations,
119 unsigned *pInlineIter
120 )
121 {
122  unsigned i;
123  int status;
124 
125  for (i=0u; i<iterations; i++) {
126  status = ca_search (pItems[i].name, &pItems[i].chix);
127  SEVCHK (status, NULL);
128  status = ca_pend_io(0.0);
129  SEVCHK (status, NULL);
130  }
131 
132  *pInlineIter = 1;
133 }
134 #endif
135 
136 /*
137  * test_free ()
138  */
139 static void test_free(
140 ti *pItems,
141 unsigned iterations,
142 unsigned *pInlineIter
143 )
144 {
145  int status;
146  unsigned i;
147 
148  for (i=0u; i<iterations; i++) {
149  status = ca_clear_channel (pItems[i].chix);
150  SEVCHK (status, NULL);
151  }
152  status = ca_flush_io();
153  SEVCHK (status, NULL);
154  *pInlineIter = 1;
155 }
156 
157 /*
158  * test_put ()
159  */
160 static void test_put(
161 ti *pItems,
162 unsigned iterations,
163 unsigned *pInlineIter
164 )
165 {
166  ti *pi;
167  int status;
168  dbr_int_t val;
169 
170  for (pi=pItems; pi < &pItems[iterations]; pi++) {
171  status = ca_array_put(
172  pi->type,
173  pi->count,
174  pi->chix,
175  pi->pValue);
176  SEVCHK (status, NULL);
177  status = ca_array_put(
178  pi->type,
179  pi->count,
180  pi->chix,
181  pi->pValue);
182  SEVCHK (status, NULL);
183  status = ca_array_put(
184  pi->type,
185  pi->count,
186  pi->chix,
187  pi->pValue);
188  SEVCHK (status, NULL);
189  status = ca_array_put(
190  pi->type,
191  pi->count,
192  pi->chix,
193  pi->pValue);
194  SEVCHK (status, NULL);
195  status = ca_array_put(
196  pi->type,
197  pi->count,
198  pi->chix,
199  pi->pValue);
200  SEVCHK (status, NULL);
201  status = ca_array_put(
202  pi->type,
203  pi->count,
204  pi->chix,
205  pi->pValue);
206  SEVCHK (status, NULL);
207  status = ca_array_put(
208  pi->type,
209  pi->count,
210  pi->chix,
211  pi->pValue);
212  SEVCHK (status, NULL);
213  status = ca_array_put(
214  pi->type,
215  pi->count,
216  pi->chix,
217  pi->pValue);
218  SEVCHK (status, NULL);
219  status = ca_array_put(
220  pi->type,
221  pi->count,
222  pi->chix,
223  pi->pValue);
224  SEVCHK (status, NULL);
225  status = ca_array_put(
226  pi->type,
227  pi->count,
228  pi->chix,
229  pi->pValue);
230  SEVCHK (status, NULL);
231  }
232 #ifdef WAIT_FOR_ACK
233  status = ca_array_get (DBR_INT, 1, pItems[0].chix, &val);
234  SEVCHK (status, NULL);
235  ca_pend_io(100.0);
236 #endif
237  status = ca_array_put(
238  pItems[0].type,
239  pItems[0].count,
240  pItems[0].chix,
241  pItems[0].pValue);
242  SEVCHK (status, NULL);
243  status = ca_flush_io();
244  SEVCHK (status, NULL);
245 
246  *pInlineIter = 10;
247 }
248 
249 /*
250  * test_get ()
251  */
252 static void test_get(
253 ti *pItems,
254 unsigned iterations,
255 unsigned *pInlineIter
256 )
257 {
258  ti *pi;
259  int status;
260 
261  for (pi=pItems; pi<&pItems[iterations]; pi++) {
262  status = ca_array_get(
263  pi->type,
264  pi->count,
265  pi->chix,
266  pi->pValue);
267  SEVCHK (status, NULL);
268  status = ca_array_get(
269  pi->type,
270  pi->count,
271  pi->chix,
272  pi->pValue);
273  SEVCHK (status, NULL);
274  status = ca_array_get(
275  pi->type,
276  pi->count,
277  pi->chix,
278  pi->pValue);
279  SEVCHK (status, NULL);
280  status = ca_array_get(
281  pi->type,
282  pi->count,
283  pi->chix,
284  pi->pValue);
285  SEVCHK (status, NULL);
286  status = ca_array_get(
287  pi->type,
288  pi->count,
289  pi->chix,
290  pi->pValue);
291  SEVCHK (status, NULL);
292  status = ca_array_get(
293  pi->type,
294  pi->count,
295  pi->chix,
296  pi->pValue);
297  SEVCHK (status, NULL);
298  status = ca_array_get(
299  pi->type,
300  pi->count,
301  pi->chix,
302  pi->pValue);
303  SEVCHK (status, NULL);
304  status = ca_array_get(
305  pi->type,
306  pi->count,
307  pi->chix,
308  pi->pValue);
309  SEVCHK (status, NULL);
310  status = ca_array_get(
311  pi->type,
312  pi->count,
313  pi->chix,
314  pi->pValue);
315  SEVCHK (status, NULL);
316  status = ca_array_get(
317  pi->type,
318  pi->count,
319  pi->chix,
320  pi->pValue);
321  SEVCHK (status, NULL);
322  }
323  status = ca_pend_io(1e20);
324  SEVCHK (status, NULL);
325 
326  *pInlineIter = 10;
327 }
328 
329 /*
330  * test_wait ()
331  */
332 static void test_wait (
333 ti *pItems,
334 unsigned iterations,
335 unsigned *pInlineIter
336 )
337 {
338  ti *pi;
339  int status;
340 
341  for (pi=pItems; pi<&pItems[iterations]; pi++) {
342  status = ca_array_get(
343  pi->type,
344  pi->count,
345  pi->chix,
346  pi->pValue);
347  SEVCHK (status, NULL);
348  status = ca_pend_io(100.0);
349  SEVCHK (status, NULL);
350  }
351 
352  *pInlineIter = 1;
353 }
354 
355 /*
356  * measure_get_latency
357  */
358 static void measure_get_latency (ti *pItems, unsigned iterations)
359 {
360  epicsTimeStamp end_time;
361  epicsTimeStamp start_time;
362  double delay;
363  double X = 0u;
364  double XX = 0u;
365  double max = DBL_MIN;
366  double min = DBL_MAX;
367  double mean;
368  double stdDev;
369  ti *pi;
370  int status;
371 
372  for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
373  epicsTimeGetCurrent ( &start_time );
374  status = ca_array_get ( pi->type, pi->count,
375  pi->chix, pi->pValue );
376  SEVCHK ( status, NULL );
377  status = ca_pend_io ( 100.0 );
378  SEVCHK ( status, NULL );
379 
380  epicsTimeGetCurrent ( &end_time );
381 
382  delay = epicsTimeDiffInSeconds ( &end_time,&start_time );
383 
384  X += delay;
385  XX += delay*delay;
386 
387  if ( delay > max ) {
388  max = delay;
389  }
390 
391  if ( delay < min ) {
392  min = delay;
393  }
394  }
395 
396  mean = X/iterations;
397  stdDev = sqrt ( XX/iterations - mean*mean );
398  printf (
399  "Get Latency - "
400  "mean = %3.1f uS, "
401  "std dev = %3.1f uS, "
402  "min = %3.1f uS "
403  "max = %3.1f uS\n",
404  mean * 1e6, stdDev * 1e6,
405  min * 1e6, max * 1e6 );
406 }
407 
408 /*
409  * printSearchStat()
410  */
411 static void printSearchStat ( const ti * pi, unsigned iterations )
412 {
413  unsigned i;
414  double X = 0u;
415  double XX = 0u;
416  double max = DBL_MIN;
417  double min = DBL_MAX;
418  double mean;
419  double stdDev;
420 
421  for ( i = 0; i < iterations; i++ ) {
422  double retry = ca_search_attempts ( pi[i].chix );
423  X += retry;
424  XX += retry * retry;
425  if ( retry > max ) {
426  max = retry;
427  }
428  if ( retry < min ) {
429  min = retry;
430  }
431  }
432 
433  mean = X / iterations;
434  stdDev = sqrt( XX / iterations - mean * mean );
435  printf (
436  "Search tries per chan - "
437  "mean = %3.1f "
438  "std dev = %3.1f "
439  "min = %3.1f "
440  "max = %3.1f\n",
441  mean, stdDev, min, max);
442 }
443 
444 /*
445  * timeIt ()
446  */
447 void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
448  unsigned nBytesSent, unsigned nBytesRecv )
449 {
450  epicsTimeStamp end_time;
451  epicsTimeStamp start_time;
452  double delay;
453  unsigned inlineIter;
454 
455  epicsTimeGetCurrent ( &start_time );
456  (*pfunc) ( pItems, iterations, &inlineIter );
457  epicsTimeGetCurrent ( &end_time );
458  delay = epicsTimeDiffInSeconds ( &end_time, &start_time );
459  if ( delay > 0.0 ) {
460  double freq = ( iterations * inlineIter ) / delay;
461  printf ( "Per Op, %8.4f uS ( %8.4f MHz )",
462  1e6 / freq, freq / 1e6 );
463  if ( pItems != NULL ) {
464  printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
465  (inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
466  (inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
467  }
468  else {
469  printf ("\n");
470  }
471  }
472 }
473 
474 /*
475  * test ()
476  */
477 static void test ( ti *pItems, unsigned iterations )
478 {
479  unsigned payloadSize, dblPayloadSize;
480  unsigned nBytesSent, nBytesRecv;
481 
482  payloadSize =
483  dbr_size_n ( pItems[0].type, pItems[0].count );
484  payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
485 
486  dblPayloadSize = dbr_size [ DBR_DOUBLE ];
487  dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
488 
489  if ( payloadSize > dblPayloadSize ) {
490  unsigned factor = payloadSize / dblPayloadSize;
491  while ( factor ) {
492  if ( iterations > 10 * factor ) {
493  iterations /= factor;
494  break;
495  }
496  factor /= 2;
497  }
498  }
499 
500  printf ( "\t### async put test ###\n");
501  nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
502  nBytesRecv = 0u;
503  timeIt ( test_put, pItems, iterations,
504  nBytesSent * iterations,
505  nBytesRecv * iterations );
506 
507  printf ( "\t### async get test ###\n");
508  nBytesSent = sizeof ( caHdr );
509  nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
510  timeIt ( test_get, pItems, iterations,
511  nBytesSent * ( iterations ),
512  nBytesRecv * ( iterations ) );
513 
514  printf ("\t### synch get test ###\n");
515  nBytesSent = sizeof ( caHdr );
516  nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
517  if ( iterations > 100 ) {
518  iterations /= 100;
519  }
520  else if ( iterations > 10 ) {
521  iterations /= 10;
522  }
523  timeIt ( test_wait, pItems, iterations,
524  nBytesSent * iterations,
525  nBytesRecv * iterations );
526 }
527 
528 /*
529  * catime ()
530  */
531 int catime ( const char * channelName,
532  unsigned channelCount, enum appendNumberFlag appNF )
533 {
534  unsigned i;
535  int j;
536  unsigned strsize;
537  unsigned nBytesSent, nBytesRecv;
538  ti *pItemList;
539 
540  if ( channelCount == 0 ) {
541  printf ( "channel count was zero\n" );
542  return 0;
543  }
544 
545  pItemList = calloc ( channelCount, sizeof (ti) );
546  if ( ! pItemList ) {
547  return -1;
548  }
549 
551  "Unable to initialize" );
552 
553  if ( appNF == appendNumber ) {
554  printf ( "Testing with %u channels named %snnn\n",
555  channelCount, channelName );
556  }
557  else {
558  printf ( "Testing with %u channels named %s\n",
559  channelCount, channelName );
560  }
561 
562  strsize = sizeof ( pItemList[0].name ) - 1;
563  nBytesSent = 0;
564  nBytesRecv = 0;
565  for ( i=0; i < channelCount; i++ ) {
566  if ( appNF == appendNumber ) {
567  sprintf ( pItemList[i].name,"%.*s%.6u",
568  (int) (strsize - 15u), channelName, i );
569  }
570  else {
571  strncpy ( pItemList[i].name, channelName, strsize);
572  }
573  pItemList[i].name[strsize]= '\0';
574  pItemList[i].count = 0;
575  pItemList[i].pValue = 0;
576  nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
577  + sizeof (caHdr) );
578  nBytesRecv += 2 * sizeof (caHdr);
579  }
580 
581  printf ( "Channel Connect Test\n" );
582  printf ( "--------------------\n" );
583  timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
584  printSearchStat ( pItemList, channelCount );
585 
586  for ( i = 0; i < channelCount; i++ ) {
587  size_t count = ca_element_count ( pItemList[i].chix );
588  size_t size = sizeof ( dbr_string_t ) * count;
589  pItemList[i].count = count;
590  pItemList[i].pValue = malloc ( size );
591  assert ( pItemList[i].pValue );
592  }
593 
594  printf (
595  "channel name=%s, native type=%d, native count=%u\n",
596  ca_name (pItemList[0].chix),
597  ca_field_type (pItemList[0].chix),
598  pItemList[0].count );
599 
600  printf ("Pend Event Test\n");
601  printf ( "----------------\n" );
602  timeIt ( test_pend, NULL, 100, 0, 0 );
603 
604  for ( i = 0; i < channelCount; i++ ) {
605  dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
606  double val = i;
607  val /= channelCount;
608  for ( j = 0; j < pItemList[i].count; j++ ) {
609  pFltVal[j] = (dbr_float_t) val;
610  }
611  pItemList[i].type = DBR_FLOAT;
612  }
613  printf ( "DBR_FLOAT Test\n" );
614  printf ( "--------------\n" );
615  test ( pItemList, channelCount );
616 
617  for ( i = 0; i < channelCount; i++ ) {
618  dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
619  double val = i;
620  val /= channelCount;
621  for ( j = 0; j < pItemList[i].count; j++ ) {
622  pDblVal[j] = (dbr_double_t) val;
623  }
624  pItemList[i].type = DBR_DOUBLE;
625  }
626  printf ( "DBR_DOUBLE Test\n" );
627  printf ( "---------------\n" );
628  test ( pItemList, channelCount );
629 
630 
631  for ( i = 0; i < channelCount; i++ ) {
632  dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
633  double val = i;
634  val /= channelCount;
635  for ( j = 0; j < pItemList[i].count; j++ ) {
636  sprintf ( pStrVal[j], "%f", val );
637  }
638  pItemList[i].type = DBR_STRING;
639  }
640  printf ( "DBR_STRING Test\n" );
641  printf ( "---------------\n" );
642  test ( pItemList, channelCount );
643 
644  for ( i = 0; i < channelCount; i++ ) {
645  dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
646  double val = i;
647  val /= channelCount;
648  for ( j = 0; j < pItemList[i].count; j++ ) {
649  pIntVal[j] = (dbr_int_t) val;
650  }
651  pItemList[i].type = DBR_INT;
652  }
653  printf ( "DBR_INT Test\n" );
654  printf ( "------------\n" );
655  test ( pItemList, channelCount );
656 
657  printf ( "Get Latency Test\n" );
658  printf ( "----------------\n" );
659  for ( i = 0; i < channelCount; i++ ) {
660  dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
661  for ( j = 0; j < pItemList[i].count; j++ ) {
662  pDblVal[j] = 0;
663  }
664  pItemList[i].type = DBR_DOUBLE;
665  }
666  measure_get_latency ( pItemList, channelCount );
667 
668  printf ( "Free Channel Test\n" );
669  printf ( "-----------------\n" );
670  timeIt ( test_free, pItemList, channelCount, 0, 0 );
671 
672  SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
673 
674  for ( i = 0; i < channelCount; i++ ) {
675  free ( pItemList[i].pValue );
676  }
677 
678  free ( pItemList );
679 
680  return CATIME_OK;
681 }
682 
683 
684 
685 
#define CATIME_OK
Definition: caDiagnostics.h:26
int epicsStdCall ca_task_exit()
Definition: access.cpp:251
#define DBR_STRING
Definition: db_access.h:69
#define max(x, y)
Definition: flexdef.h:81
const unsigned short dbr_size[LAST_BUFFER_TYPE+1]
Definition: access.cpp:847
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
int i
Definition: scan.c:967
#define min(x, y)
Definition: flexdef.h:78
int count
Definition: catime.c:47
LIBCA_API unsigned long epicsStdCall ca_element_count(chid chan)
epicsFloat32 dbr_float_t
Definition: db_access.h:46
#define DBR_FLOAT
Definition: db_access.h:72
int epicsStdCall ca_pend_io(ca_real timeout)
Definition: access.cpp:484
#define printf
Definition: epicsStdio.h:41
#define DBR_INT
Definition: db_access.h:70
#define NULL
Definition: catime.c:38
appendNumberFlag
Definition: caDiagnostics.h:19
int catime(const char *channelName, unsigned channelCount, enum appendNumberFlag appNF)
Definition: catime.c:531
LIBCA_API short epicsStdCall ca_field_type(chid chan)
void * pValue
Definition: catime.c:48
void timeIt(tf *pfunc, ti *pItems, unsigned iterations, unsigned nBytesSent, unsigned nBytesRecv)
Definition: catime.c:447
int epicsStdCall ca_context_create(ca_preemptive_callback_select premptiveCallbackSelect)
Definition: access.cpp:172
int epicsStdCall ca_pend_event(ca_real timeout)
Definition: access.cpp:457
char name[128]
Definition: catime.c:45
#define ECA_NORMAL
Definition: caerr.h:77
#define CA_MESSAGE_ALIGN(A)
Definition: caProto.h:154
LIBCA_API int epicsStdCall ca_array_put(chtype type, unsigned long count, chid chanId, const void *pValue)
int epicsStdCall ca_flush_io()
Definition: access.cpp:509
#define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING)
Definition: cadef.h:137
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
#define DBR_DOUBLE
Definition: db_access.h:76
LIBCA_API int epicsStdCall ca_array_get(chtype type, unsigned long count, chid chanId, void *pValue)
epicsFloat64 dbr_double_t
Definition: db_access.h:47
LIBCA_API const char *epicsStdCall ca_name(chid chan)
void tf(ti *pItems, unsigned iterations, unsigned *pInlineIter)
Definition: catime.c:51
epicsOldString dbr_string_t
Definition: db_access.h:38
int epicsStdCall ca_clear_channel(chid pChan)
Definition: access.cpp:363
#define ca_search(pChanName, pChanID)
Definition: cadef.h:859
epicsInt16 dbr_int_t
Definition: db_access.h:42
struct ca_hdr caHdr
chid chix
Definition: catime.c:44
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
#define dbr_size_n(TYPE, COUNT)
Definition: db_access.h:518
#define ECA_TIMEOUT
Definition: caerr.h:87
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
Definition: epicsTime.cpp:1048
int type
Definition: catime.c:46
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
LIBCA_API unsigned epicsStdCall ca_search_attempts(chid chan)
struct testItem ti