2 //=============================================================================
4 * @file CDR_Array_Test.cpp
6 * Checks ACE_OutputCDR::write_XX_array.
7 * Checks ACE_InputCDR::read_XX_array.
8 * Checks operator<< and operator>> for CDR Streams in
9 * each of the basic CDR types.
10 * Gives a measure of the speed of the ACE CDR streams wrt those
13 * @author Cristian Ferretti <cristian_ferretti@yahoo.com>
15 //=============================================================================
18 // For measuring time, choose your method:
21 // * USE_GETRUSAGE for using ACE_OS::getrusage.
22 // Ticks only when process is running.
24 // * USE_CLOCK for using clock(2).
25 // You're on your own, no ACE_OS:: support.
26 // Ticks only when process is running.
28 // * None of the above for using ACE_High_Res_Timer.
29 // Ticks independent of running state of process.
32 // #define USE_GETRUSAGE
34 #if defined(USE_CLOCK)
38 #include "test_config.h"
39 #include "ace/OS_Memory.h"
40 #include "ace/OS_NS_stdlib.h"
41 #include "ace/Get_Opt.h"
42 #include "ace/CDR_Stream.h"
43 #include "ace/High_Res_Timer.h"
46 #if defined(USE_GETRUSAGE) && !defined(ACE_HAS_GETRUSAGE)
47 #error "Can't define USE_GETRUSAGE on this platform."
51 // Default number of elements for check buffer, for each tested CDR type.
52 // Be aware that time will be affected by the buffer fitting/not fitting
53 // in the cache (ie, if default_total*sizeof(T) bytes fit in the cache).
54 // Also, you want that your time measuring method has a resolution
55 // compatible with this buffer size, if not you will end up measuring 0.
56 // You can change this value with -t option.
57 static const int default_total
= 32*1024;
59 // Repeat this many times for each tested CDR type.
60 // We then take the average time that took for each type and report that.
61 // You can change this value with -n option.
62 static const int default_niter
= 10;
65 // A simple cronometer in seconds, that encapsulates our time
74 #if defined(USE_CLOCK)
76 #elif defined(USE_GETRUSAGE)
77 ACE_OS::getrusage (RUSAGE_SELF
, &start_
);
84 #if defined(USE_CLOCK)
86 #elif defined(USE_GETRUSAGE)
87 ACE_OS::getrusage (RUSAGE_SELF
, &end_
);
92 double read_seconds ()
94 #if defined(USE_CLOCK)
95 return (end_
- start_
) / (double) CLOCKS_PER_SEC
;
96 #elif defined(USE_GETRUSAGE)
98 diff
.tv_sec
= end_
.ru_utime
.tv_sec
- start_
.ru_utime
.tv_sec
;
99 diff
.tv_usec
= end_
.ru_utime
.tv_usec
- start_
.ru_utime
.tv_usec
;
100 while (diff
.tv_usec
< 0)
103 diff
.tv_usec
+= ACE_ONE_SECOND_IN_USECS
;
106 return diff
.tv_sec
+ diff
.tv_usec
/ double(ACE_ONE_SECOND_IN_USECS
);
109 timer
.elapsed_time(tv
);
110 return tv
.usec () / 1000000.0;
114 #if defined(USE_CLOCK)
117 #elif defined(USE_GETRUSAGE)
121 ACE_High_Res_Timer timer
;
126 // Our test, performed in the constructor.
127 // T is one of the CDR types.
128 // H is a helper class (described later).
130 // All this stuff is in a class and not in template functions
131 // to avoid having to deal with potential template function
132 // instantiations problems.
134 template<class T
, class H
> class CDR_Test
137 CDR_Test (int total
, int niter
, int use_array
);
138 static void do_test (int total
, int niter
, int use_array
,
139 char* srcbuf
, char* dstbuf
,
140 int src_offset
= 0, int dst_offset
= 0);
143 static void ttoh (const T
& t
, char* s
);
144 static T
checkval(int i
);
147 CDR_Test (const CDR_Test
<T
, H
>&);
148 CDR_Test
<T
, H
>& operator= (const CDR_Test
<T
, H
>&);
151 static ACE_UINT32 seal
= 0xdeadbeef;
154 zero (char* p
, size_t k
)
166 return (a
>= b
) ? a
: b
;
173 ACE_TEXT ("new failed, aborting\n")));
177 template<class T
, class H
>
178 CDR_Test
<T
, H
>::CDR_Test (int total
, int niter
, int use_array
)
188 const size_t stotal
=
189 (total
+ 10) * H::size () + sizeof(ACE_UINT32
) + ACE_CDR::MAX_ALIGNMENT
;
191 ACE_NEW(srcbuf
, char[stotal
]);
196 zero(srcbuf
, stotal
);
198 ACE_NEW(dstbuf
, char[stotal
]);
203 zero(dstbuf
, stotal
);
208 // We want to test all the possible loop unrolling deltas.
210 for (t
= total
- 3; t
<= total
; t
++)
213 if (sizeof(long) <= H::size ())
219 delta
= (int) (sizeof(long) / H::size ());
222 // We want to test all the posible source/destination buffer
223 // alignment combinations.
225 for (sk
= 0; sk
< delta
; sk
++)
228 for (dk
= 0; dk
< delta
; dk
++)
230 int tdelta
= t
- mymax(sk
, dk
);
232 CDR_Test
<T
, H
>::do_test(tdelta
, niter
, 1,
241 do_test(total
, niter
, use_array
, srcbuf
, dstbuf
);
248 // Generate an ``interesting'' value for testing at pos >i<.
249 template<class T
, class H
> T
250 CDR_Test
<T
, H
>::checkval (int i
)
254 // If T is not an integral type, we don't want to risk
255 // getting an invalid bit pattern for a T value.
261 unsigned char* s
= reinterpret_cast<unsigned char*> ((&v
));
263 for (j
= 0; j
< H::size (); j
++)
265 s
[j
] = (unsigned char) ((j
+ i
* H::size ()) % 256);
273 // Returns in s an hex representation of T's memory.
274 // (differences in byte order will be noticed in s).
278 // => s = "aabbccdd" for big endian machines,
279 // s = "ddccbbaa" for little endian machines.
281 template<class T
, class H
> void
282 CDR_Test
<T
, H
>::ttoh (const T
& t
, char* s
)
284 const unsigned char *const p
=
285 reinterpret_cast<const unsigned char*> (&t
);
287 static char digits
[16] = {
294 const unsigned char* q
;
295 for (q
= p
; q
< p
+ H::size (); ++q
)
298 *s
++ = digits
[ k
>> 4 ];
299 *s
++ = digits
[ k
& 15 ];
308 char* ps
= reinterpret_cast<char*> (&seal
);
316 check_seal (char* pos
)
318 char* ps
= reinterpret_cast<char*> (&seal
);
319 return (pos
[0] == ps
[0]
326 // returns the alignment of ptr, wrt ACE_CDR::MAX_ALIGNMENT.
329 tellalign (const char* const ptr
)
331 int align
= ACE_CDR::MAX_ALIGNMENT
;
332 while (ptr
!= ACE_ptr_align_binary(ptr
, align
))
340 template<class T
, class H
> void
341 CDR_Test
<T
, H
>::do_test (int total
, int niter
, int use_array
,
342 char* srcbuf
, char* dstbuf
,
343 int src_offset
, int dst_offset
)
347 dst_offset
= src_offset
= 0;
351 ACE_TEXT( "Starting Test for %s: %d elements " )
352 ACE_TEXT( "%susing arrays.\n" ),
355 ((use_array
) ? ACE_TEXT( "" ) : ACE_TEXT( "not " ))));
358 if (!use_array
&& (total
% 4) != 0)
360 int lasttotal
= total
;
361 total
-= (total
% 4);
363 ACE_TEXT( "Rounding from %d to %d elements.\n" ),
368 char* src
= ACE_ptr_align_binary(srcbuf
, H::size ());
369 T
* idata
= reinterpret_cast<T
*> (src
);
371 src
= reinterpret_cast<char*> (idata
);
375 for (i
= 0; i
< total
; i
++)
377 idata
[i
] = CDR_Test
<T
, H
>::checkval (i
);
382 ACE_TEXT( "Writing data...\n" )));
386 ACE_TEST_ASSERT(use_array
|| total
% 4 == 0);
388 double totalsecs
= 0.0;
390 for (n
= 0; n
< niter
; n
++)
392 size_t size
= H::size () * (dst_offset
+ total
) +
393 ACE_CDR::MAX_ALIGNMENT
;
394 ACE_OutputCDR
os (dstbuf
, size
);
396 // This is intrusive...
397 char* const end
= os
.begin ()->wr_ptr() + size
;
406 for (i
= 0; i
< dst_offset
; i
++)
415 ACE_TEXT ("* src align = %d, dst align = %d\n"),
417 tellalign (os
.begin ()->wr_ptr ())));
422 H::write_array (os
, idata
, total
);
424 secs
= crono
.read_seconds ();
429 for (; i
< dst_offset
; i
++)
443 // static char rs[32 + 1];
444 // CDR_Test<T,H>::ttoh (idata[i], rs);
445 // ACE_DEBUG ((LM_DEBUG, "Write idata[%d] = %s\n", i, rs));
450 secs
= crono
.read_seconds ();
453 if (!check_seal(end
))
456 ACE_TEXT( "Broken seal, aborting.\n" )));
464 toread
= os
.begin ()->rd_ptr ();
468 totalsecs
= totalsecs
/ niter
;
471 ACE_TEXT ("Writing to stream %d %s values: %f seconds.\n"),
479 for (i
= 0; i
< total
; i
++)
486 ACE_TEXT( "Reading them back in opposing byte order...\n" )));
488 const int opposite_byte_order
= 1 - ACE_CDR_BYTE_ORDER
;
491 double totalsecs
= 0.0;
493 for (n
= 0; n
< niter
; n
++)
495 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("====== Read iteration %d\n"), n
));
497 size_t size
= (total
+ dst_offset
) * H::size ();
498 ACE_InputCDR
is (toread
, size
, opposite_byte_order
);
500 // This is intrusive...
501 char* const end
= is
.rd_ptr () + size
;
510 for (i
= 0; i
< dst_offset
; i
++)
520 ACE_TEXT ("* src align = %d, dst align = %d\n"),
521 tellalign (is
.rd_ptr ()),
527 H::read_array (is
, idata
, total
);
529 secs
= crono
.read_seconds ();
531 // Testing for good bit value. Try reading atleast 10
532 // times the size of total. It should fail with good bit
534 H::read_array (is
, idata
, 10 * total
);
536 if (is
.good_bit () != 0)
538 ACE_ERROR ((LM_ERROR
,
539 ACE_TEXT ("Test for good bit failed in %s Array_test\n"),
553 static char rs
[32 + 1];
554 CDR_Test
<T
,H
>::ttoh (v
, rs
);
555 ACE_DEBUG ((LM_DEBUG
, "Read idata[%d] = %s\n", i
, rs
));
566 secs
= crono
.read_seconds ();
570 if (!check_seal (end
))
573 ACE_TEXT( "Broken seal, aborting.\n" )));
578 totalsecs
= totalsecs
/ niter
;
581 ACE_TEXT ("Reading from stream %d %s values")
582 ACE_TEXT (" (byte swapping): %f seconds.\n"),
589 ACE_TEXT ("Now checking data...\n") ));
592 const int maxerrors
= 6;
596 for (i
= 0; i
< total
; i
++)
600 const char* src
= reinterpret_cast<const char*> ((idata
+ i
));
601 char* dst
= reinterpret_cast<char*> ((&rv
));
605 // Due to a "feature" of the gcc 4.1.1 optimizer, we need to do
606 // something with the src pointer so that it doesn't optimize it
607 // away. Calling tellalign() is benign, but the optimizer
608 // doesn't know/care. -- Chad Elliott 1/10/2007
611 T cv
= CDR_Test
<T
, H
>::checkval (i
);
612 if (!ACE::is_equal (rv
, cv
))
614 static char rs
[32 + 1];
615 static char cs
[32 + 1];
616 CDR_Test
<T
, H
>::ttoh (rv
, rs
);
617 CDR_Test
<T
, H
>::ttoh (cv
, cs
);
619 ACE_TEXT ( "Wrong value at pos %d:" )
620 ACE_TEXT ( " '%C' should be '%C'.\n" ),
623 if (errors
== maxerrors
)
626 ACE_TEXT ( "%d errors found, ")
627 ACE_TEXT ( "interrupting check.\n" ),
638 ACE_TEXT (" assertion failed: Inconsistencies found (%d), ")
639 ACE_TEXT ("aborting.\n"), errors
));
644 ACE_TEXT ("Data OK, test %s completed.\n"),
648 template <class T
, class N
>
649 CDR_Test
<T
, N
>::~CDR_Test ()
654 // Helper Clases for the second template parameter of CDR_Test.
655 // One for each tested CDR type.
660 static const ACE_TCHAR
* name ()
662 return ACE_TEXT ("CDR::Double");
664 static int integral ()
668 static void read_array (ACE_InputCDR
& is
,
672 is
.read_double_array (x
, n
);
674 static void write_array (ACE_OutputCDR
& os
,
678 os
.write_double_array (x
, n
);
680 static void swap (const char *src
, char *dst
)
682 ACE_CDR::swap_8 (src
, dst
);
684 static size_t size ()
686 return sizeof(ACE_CDR::Double
);
692 static const ACE_TCHAR
* name ()
694 return ACE_TEXT ("CDR::Float");
696 static int integral ()
700 static void read_array (ACE_InputCDR
& is
,
704 is
.read_float_array (x
, n
);
706 static void write_array (ACE_OutputCDR
& os
,
710 os
.write_float_array (x
, n
);
712 static void swap (const char *src
, char *dst
)
714 ACE_CDR::swap_4 (src
, dst
);
716 static size_t size ()
718 return sizeof(ACE_CDR::Float
);
724 static const ACE_TCHAR
* name ()
726 return ACE_TEXT ("CDR::Short");
728 static int integral ()
732 static void read_array (ACE_InputCDR
& is
,
736 is
.read_short_array (x
, n
);
738 static void write_array (ACE_OutputCDR
& os
,
742 os
.write_short_array (x
, n
);
744 static void swap (const char *src
, char *dst
)
746 ACE_CDR::swap_2 (src
, dst
);
748 static size_t size ()
750 return sizeof(ACE_CDR::Short
);
756 static const ACE_TCHAR
* name ()
758 return ACE_TEXT ("CDR::Long");
760 static int integral ()
764 static void read_array (ACE_InputCDR
& is
,
768 is
.read_long_array (x
, n
);
770 static void write_array (ACE_OutputCDR
& os
,
774 os
.write_long_array (x
, n
);
776 static void swap (const char *src
, char *dst
)
778 ACE_CDR::swap_4 (src
, dst
);
780 static size_t size ()
782 return sizeof(ACE_CDR::Long
);
786 struct LongLongHelper
788 static const ACE_TCHAR
* name ()
790 return ACE_TEXT ("CDR::LongLong");
792 static int integral ()
796 static void read_array (ACE_InputCDR
& is
,
797 ACE_CDR::LongLong
* x
,
800 is
.read_longlong_array (x
, n
);
802 static void write_array (ACE_OutputCDR
& os
,
803 ACE_CDR::LongLong
* x
,
806 os
.write_longlong_array (x
, n
);
809 static void swap (const char *src
, char *dst
)
811 ACE_CDR::swap_8 (src
, dst
);
813 static size_t size ()
815 return sizeof(ACE_CDR::LongLong
);
821 static const ACE_TCHAR
* name ()
823 return ACE_TEXT ("CDR::Char");
825 static int integral ()
829 static void read_array (ACE_InputCDR
& is
,
833 is
.read_char_array (x
, n
);
835 static void write_array (ACE_OutputCDR
& os
,
839 os
.write_char_array (x
, n
);
841 static void swap (const char *src
, char *dst
)
845 static size_t size ()
847 return sizeof(ACE_CDR::Char
);
851 void usage (const ACE_TCHAR
* cmd
)
854 ACE_TEXT ("Usage: %s ")
855 ACE_TEXT ("[-n n] " )
856 ACE_TEXT ("[[-d n|-f n|-q n|-w n|-h n|-c n|-t n] | [-t n]]\n")
857 ACE_TEXT (" -n n: average time for n iterations.\n")
858 ACE_TEXT (" -d n: n double precision floating point\n")
859 ACE_TEXT (" -f n: n single precision floating point\n")
860 ACE_TEXT (" -q n: n quadwords (int64).\n")
861 ACE_TEXT (" -w n: n words (int32).\n")
862 ACE_TEXT (" -h n: n halfwords (int16).\n")
863 ACE_TEXT (" -c n: n chars.\n")
864 ACE_TEXT (" -t n: n iterations for every type.\n")
865 ACE_TEXT (" n must be >= 16 for dfqwhct.\n")
866 ACE_TEXT (" If you provide one of dfqwhc, then only the\n")
867 ACE_TEXT (" test for the corresponding type ")
868 ACE_TEXT ("will be performed.\n"),
886 run_main (int argc
, ACE_TCHAR
*argv
[])
888 ACE_START_TEST (ACE_TEXT ("CDR_Array_Test"));
890 ACE_DEBUG ((LM_DEBUG
,
891 ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
892 ACE::major_version (),
893 ACE::minor_version(),
894 ACE::micro_version()));
896 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("d:f:q:w:h:c:t:n:"));
906 struct { int c
; int *v
; int (*checkf
)(int); } opts
[] = {
907 { 'd', &dtotal
, validtotal
},
908 { 'f', &ftotal
, validtotal
},
909 { 'q', &qtotal
, validtotal
},
910 { 'w', &wtotal
, validtotal
},
911 { 'h', &htotal
, validtotal
},
912 { 'c', &ctotal
, validtotal
},
913 { 't', &total
, validtotal
},
914 { 'n', &niter
, validiters
},
917 int n
= sizeof(opts
)/sizeof(opts
[0]);
920 while ((opt
= get_opt ()) != EOF
)
924 for (i
= 0; i
< n
; i
++)
926 if (opts
[i
].c
== opt
)
928 int v
= ACE_OS::atoi (get_opt
.opt_arg ());
929 if (!(opts
[i
].checkf
) (v
))
931 usage(ACE_TEXT("CDR_Array_Test"));
942 usage(ACE_TEXT("CDR_Array_Test"));
948 total
= default_total
;
953 niter
= default_niter
;
963 dtotal
= ftotal
= qtotal
= wtotal
= htotal
= ctotal
= total
;
967 for (use_array
= 0; use_array
< 2; use_array
++)
970 CDR_Test
<ACE_CDR::LongLong
, LongLongHelper
>
971 test (qtotal
, niter
, use_array
);
974 CDR_Test
<ACE_CDR::Long
, LongHelper
>
975 test (wtotal
, niter
, use_array
);
978 CDR_Test
<ACE_CDR::Short
, ShortHelper
>
979 test (htotal
, niter
, use_array
);
982 CDR_Test
<ACE_CDR::Char
, CharHelper
>
983 test (ctotal
, niter
, use_array
);
986 CDR_Test
<ACE_CDR::Double
, DoubleHelper
>
987 test (dtotal
, niter
, use_array
);
990 CDR_Test
<ACE_CDR::Float
, FloatHelper
>
991 test (ftotal
, niter
, use_array
);