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."
52 // Default number of elements for check buffer, for each tested CDR type.
53 // Be aware that time will be affected by the buffer fitting/not fitting
54 // in the cache (ie, if default_total*sizeof(T) bytes fit in the cache).
55 // Also, you want that your time measuring method has a resolution
56 // compatible with this buffer size, if not you will end up measuring 0.
57 // You can change this value with -t option.
58 static const int default_total
= 32*1024;
60 // Repeat this many times for each tested CDR type.
61 // We then take the average time that took for each type and report that.
62 // You can change this value with -n option.
63 static const int default_niter
= 10;
66 // A simple cronometer in seconds, that encapsulates our time
75 #if defined(USE_CLOCK)
77 #elif defined(USE_GETRUSAGE)
78 ACE_OS::getrusage (RUSAGE_SELF
, &start_
);
85 #if defined(USE_CLOCK)
87 #elif defined(USE_GETRUSAGE)
88 ACE_OS::getrusage (RUSAGE_SELF
, &end_
);
93 double read_seconds ()
95 #if defined(USE_CLOCK)
96 return (end_
- start_
) / (double) CLOCKS_PER_SEC
;
97 #elif defined(USE_GETRUSAGE)
99 diff
.tv_sec
= end_
.ru_utime
.tv_sec
- start_
.ru_utime
.tv_sec
;
100 diff
.tv_usec
= end_
.ru_utime
.tv_usec
- start_
.ru_utime
.tv_usec
;
101 while (diff
.tv_usec
< 0)
104 diff
.tv_usec
+= ACE_ONE_SECOND_IN_USECS
;
107 return diff
.tv_sec
+ diff
.tv_usec
/ double(ACE_ONE_SECOND_IN_USECS
);
110 timer
.elapsed_time(tv
);
111 return tv
.usec () / 1000000.0;
115 #if defined(USE_CLOCK)
118 #elif defined(USE_GETRUSAGE)
122 ACE_High_Res_Timer timer
;
127 // Our test, performed in the constructor.
128 // T is one of the CDR types.
129 // H is a helper class (described later).
131 // All this stuff is in a class and not in template functions
132 // to avoid having to deal with potential template function
133 // instantiations problems.
135 template<class T
, class H
> class CDR_Test
138 CDR_Test (int total
, int niter
, int use_array
);
139 static void do_test (int total
, int niter
, int use_array
,
140 char* srcbuf
, char* dstbuf
,
141 int src_offset
= 0, int dst_offset
= 0);
144 static void ttoh (const T
& t
, char* s
);
145 static T
checkval(int i
);
148 CDR_Test (const CDR_Test
<T
, H
>&);
149 CDR_Test
<T
, H
>& operator= (const CDR_Test
<T
, H
>&);
152 static ACE_UINT32 seal
= 0xdeadbeef;
155 zero (char* p
, size_t k
)
167 return (a
>= b
) ? a
: b
;
174 ACE_TEXT ("new failed, aborting\n")));
178 template<class T
, class H
>
179 CDR_Test
<T
, H
>::CDR_Test (int total
, int niter
, int use_array
)
189 const size_t stotal
=
190 (total
+ 10) * H::size () + sizeof(ACE_UINT32
) + ACE_CDR::MAX_ALIGNMENT
;
192 ACE_NEW(srcbuf
, char[stotal
]);
197 zero(srcbuf
, stotal
);
199 ACE_NEW(dstbuf
, char[stotal
]);
204 zero(dstbuf
, stotal
);
209 // We want to test all the possible loop unrolling deltas.
211 for (t
= total
- 3; t
<= total
; t
++)
214 if (sizeof(long) <= H::size ())
220 delta
= (int) (sizeof(long) / H::size ());
223 // We want to test all the posible source/destination buffer
224 // alignment combinations.
226 for (sk
= 0; sk
< delta
; sk
++)
229 for (dk
= 0; dk
< delta
; dk
++)
231 int tdelta
= t
- mymax(sk
, dk
);
233 CDR_Test
<T
, H
>::do_test(tdelta
, niter
, 1,
243 do_test(total
, niter
, use_array
, srcbuf
, dstbuf
);
250 // Generate an ``interesting'' value for testing at pos >i<.
251 template<class T
, class H
> T
252 CDR_Test
<T
, H
>::checkval (int i
)
256 // If T is not an integral type, we don't want to risk
257 // getting an invalid bit pattern for a T value.
263 unsigned char* s
= reinterpret_cast<unsigned char*> ((&v
));
265 for (j
= 0; j
< H::size (); j
++)
267 s
[j
] = (unsigned char) ((j
+ i
* H::size ()) % 256);
275 // Returns in s an hex representation of T's memory.
276 // (differences in byte order will be noticed in s).
280 // => s = "aabbccdd" for big endian machines,
281 // s = "ddccbbaa" for little endian machines.
283 template<class T
, class H
> void
284 CDR_Test
<T
, H
>::ttoh (const T
& t
, char* s
)
286 const unsigned char *const p
=
287 reinterpret_cast<const unsigned char*> (&t
);
289 static char digits
[16] = {
296 const unsigned char* q
;
297 for (q
= p
; q
< p
+ H::size (); ++q
)
300 *s
++ = digits
[ k
>> 4 ];
301 *s
++ = digits
[ k
& 15 ];
310 char* ps
= reinterpret_cast<char*> (&seal
);
318 check_seal (char* pos
)
320 char* ps
= reinterpret_cast<char*> (&seal
);
321 return (pos
[0] == ps
[0]
328 // returns the alignment of ptr, wrt ACE_CDR::MAX_ALIGNMENT.
331 tellalign (const char* const ptr
)
333 int align
= ACE_CDR::MAX_ALIGNMENT
;
334 while (ptr
!= ACE_ptr_align_binary(ptr
, align
))
342 template<class T
, class H
> void
343 CDR_Test
<T
, H
>::do_test (int total
, int niter
, int use_array
,
344 char* srcbuf
, char* dstbuf
,
345 int src_offset
, int dst_offset
)
349 dst_offset
= src_offset
= 0;
353 ACE_TEXT( "Starting Test for %s: %d elements " )
354 ACE_TEXT( "%susing arrays.\n" ),
357 ((use_array
) ? ACE_TEXT( "" ) : ACE_TEXT( "not " ))));
360 if (!use_array
&& (total
% 4) != 0)
362 int lasttotal
= total
;
363 total
-= (total
% 4);
365 ACE_TEXT( "Rounding from %d to %d elements.\n" ),
370 char* src
= ACE_ptr_align_binary(srcbuf
, H::size ());
371 T
* idata
= reinterpret_cast<T
*> (src
);
373 src
= reinterpret_cast<char*> (idata
);
377 for (i
= 0; i
< total
; i
++)
379 idata
[i
] = CDR_Test
<T
, H
>::checkval (i
);
384 ACE_TEXT( "Writing data...\n" )));
388 ACE_TEST_ASSERT(use_array
|| total
% 4 == 0);
390 double totalsecs
= 0.0;
392 for (n
= 0; n
< niter
; n
++)
394 size_t size
= H::size () * (dst_offset
+ total
) +
395 ACE_CDR::MAX_ALIGNMENT
;
396 ACE_OutputCDR
os (dstbuf
, size
);
398 // This is intrusive...
399 char* const end
= os
.begin ()->wr_ptr() + size
;
408 for (i
= 0; i
< dst_offset
; i
++)
417 ACE_TEXT ("* src align = %d, dst align = %d\n"),
419 tellalign (os
.begin ()->wr_ptr ())));
424 H::write_array (os
, idata
, total
);
426 secs
= crono
.read_seconds ();
431 for (; i
< dst_offset
; i
++)
445 // static char rs[32 + 1];
446 // CDR_Test<T,H>::ttoh (idata[i], rs);
447 // ACE_DEBUG ((LM_DEBUG, "Write idata[%d] = %s\n", i, rs));
452 secs
= crono
.read_seconds ();
455 if (!check_seal(end
))
458 ACE_TEXT( "Broken seal, aborting.\n" )));
466 toread
= os
.begin ()->rd_ptr ();
470 totalsecs
= totalsecs
/ niter
;
473 ACE_TEXT ("Writing to stream %d %s values: %f seconds.\n"),
481 for (i
= 0; i
< total
; i
++)
488 ACE_TEXT( "Reading them back in opposing byte order...\n" )));
490 const int opposite_byte_order
= 1 - ACE_CDR_BYTE_ORDER
;
493 double totalsecs
= 0.0;
495 for (n
= 0; n
< niter
; n
++)
497 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("====== Read iteration %d\n"), n
));
499 size_t size
= (total
+ dst_offset
) * H::size ();
500 ACE_InputCDR
is (toread
, size
, opposite_byte_order
);
502 // This is intrusive...
503 char* const end
= is
.rd_ptr () + size
;
512 for (i
= 0; i
< dst_offset
; i
++)
522 ACE_TEXT ("* src align = %d, dst align = %d\n"),
523 tellalign (is
.rd_ptr ()),
529 H::read_array (is
, idata
, total
);
531 secs
= crono
.read_seconds ();
533 // Testing for good bit value. Try reading atleast 10
534 // times the size of total. It should fail with good bit
536 H::read_array (is
, idata
, 10 * total
);
538 if (is
.good_bit () != 0)
540 ACE_ERROR ((LM_ERROR
,
541 ACE_TEXT ("Test for good bit failed in %s Array_test\n"),
555 static char rs
[32 + 1];
556 CDR_Test
<T
,H
>::ttoh (v
, rs
);
557 ACE_DEBUG ((LM_DEBUG
, "Read idata[%d] = %s\n", i
, rs
));
568 secs
= crono
.read_seconds ();
572 if (!check_seal (end
))
575 ACE_TEXT( "Broken seal, aborting.\n" )));
580 totalsecs
= totalsecs
/ niter
;
583 ACE_TEXT ("Reading from stream %d %s values")
584 ACE_TEXT (" (byte swapping): %f seconds.\n"),
591 ACE_TEXT ("Now checking data...\n") ));
594 const int maxerrors
= 6;
598 for (i
= 0; i
< total
; i
++)
602 const char* src
= reinterpret_cast<const char*> ((idata
+ i
));
603 char* dst
= reinterpret_cast<char*> ((&rv
));
607 // Due to a "feature" of the gcc 4.1.1 optimizer, we need to do
608 // something with the src pointer so that it doesn't optimize it
609 // away. Calling tellalign() is benign, but the optimizer
610 // doesn't know/care. -- Chad Elliott 1/10/2007
613 T cv
= CDR_Test
<T
, H
>::checkval (i
);
614 if (!ACE::is_equal (rv
, cv
))
616 static char rs
[32 + 1];
617 static char cs
[32 + 1];
618 CDR_Test
<T
, H
>::ttoh (rv
, rs
);
619 CDR_Test
<T
, H
>::ttoh (cv
, cs
);
621 ACE_TEXT ( "Wrong value at pos %d:" )
622 ACE_TEXT ( " '%C' should be '%C'.\n" ),
625 if (errors
== maxerrors
)
628 ACE_TEXT ( "%d errors found, ")
629 ACE_TEXT ( "interrupting check.\n" ),
640 ACE_TEXT (" assertion failed: Inconsistencies found (%d), ")
641 ACE_TEXT ("aborting.\n"), errors
));
646 ACE_TEXT ("Data OK, test %s completed.\n"),
650 template <class T
, class N
>
651 CDR_Test
<T
, N
>::~CDR_Test ()
656 // Helper Clases for the second template parameter of CDR_Test.
657 // One for each tested CDR type.
662 static const ACE_TCHAR
* name ()
664 return ACE_TEXT ("CDR::Double");
666 static int integral ()
670 static void read_array (ACE_InputCDR
& is
,
674 is
.read_double_array (x
, n
);
676 static void write_array (ACE_OutputCDR
& os
,
680 os
.write_double_array (x
, n
);
682 static void swap (const char *src
, char *dst
)
684 ACE_CDR::swap_8 (src
, dst
);
686 static size_t size ()
688 return sizeof(ACE_CDR::Double
);
694 static const ACE_TCHAR
* name ()
696 return ACE_TEXT ("CDR::Float");
698 static int integral ()
702 static void read_array (ACE_InputCDR
& is
,
706 is
.read_float_array (x
, n
);
708 static void write_array (ACE_OutputCDR
& os
,
712 os
.write_float_array (x
, n
);
714 static void swap (const char *src
, char *dst
)
716 ACE_CDR::swap_4 (src
, dst
);
718 static size_t size ()
720 return sizeof(ACE_CDR::Float
);
726 static const ACE_TCHAR
* name ()
728 return ACE_TEXT ("CDR::Short");
730 static int integral ()
734 static void read_array (ACE_InputCDR
& is
,
738 is
.read_short_array (x
, n
);
740 static void write_array (ACE_OutputCDR
& os
,
744 os
.write_short_array (x
, n
);
746 static void swap (const char *src
, char *dst
)
748 ACE_CDR::swap_2 (src
, dst
);
750 static size_t size ()
752 return sizeof(ACE_CDR::Short
);
758 static const ACE_TCHAR
* name ()
760 return ACE_TEXT ("CDR::Long");
762 static int integral ()
766 static void read_array (ACE_InputCDR
& is
,
770 is
.read_long_array (x
, n
);
772 static void write_array (ACE_OutputCDR
& os
,
776 os
.write_long_array (x
, n
);
778 static void swap (const char *src
, char *dst
)
780 ACE_CDR::swap_4 (src
, dst
);
782 static size_t size ()
784 return sizeof(ACE_CDR::Long
);
788 struct LongLongHelper
790 static const ACE_TCHAR
* name ()
792 return ACE_TEXT ("CDR::LongLong");
794 static int integral ()
798 static void read_array (ACE_InputCDR
& is
,
799 ACE_CDR::LongLong
* x
,
802 is
.read_longlong_array (x
, n
);
804 static void write_array (ACE_OutputCDR
& os
,
805 ACE_CDR::LongLong
* x
,
808 os
.write_longlong_array (x
, n
);
811 static void swap (const char *src
, char *dst
)
813 ACE_CDR::swap_8 (src
, dst
);
815 static size_t size ()
817 return sizeof(ACE_CDR::LongLong
);
823 static const ACE_TCHAR
* name ()
825 return ACE_TEXT ("CDR::Char");
827 static int integral ()
831 static void read_array (ACE_InputCDR
& is
,
835 is
.read_char_array (x
, n
);
837 static void write_array (ACE_OutputCDR
& os
,
841 os
.write_char_array (x
, n
);
843 static void swap (const char *src
, char *dst
)
847 static size_t size ()
849 return sizeof(ACE_CDR::Char
);
853 void usage (const ACE_TCHAR
* cmd
)
856 ACE_TEXT ("Usage: %s ")
857 ACE_TEXT ("[-n n] " )
858 ACE_TEXT ("[[-d n|-f n|-q n|-w n|-h n|-c n|-t n] | [-t n]]\n")
859 ACE_TEXT (" -n n: average time for n iterations.\n")
860 ACE_TEXT (" -d n: n double precision floating point\n")
861 ACE_TEXT (" -f n: n single precision floating point\n")
862 ACE_TEXT (" -q n: n quadwords (int64).\n")
863 ACE_TEXT (" -w n: n words (int32).\n")
864 ACE_TEXT (" -h n: n halfwords (int16).\n")
865 ACE_TEXT (" -c n: n chars.\n")
866 ACE_TEXT (" -t n: n iterations for every type.\n")
867 ACE_TEXT (" n must be >= 16 for dfqwhct.\n")
868 ACE_TEXT (" If you provide one of dfqwhc, then only the\n")
869 ACE_TEXT (" test for the corresponding type ")
870 ACE_TEXT ("will be performed.\n"),
888 run_main (int argc
, ACE_TCHAR
*argv
[])
890 ACE_START_TEST (ACE_TEXT ("CDR_Array_Test"));
892 ACE_DEBUG ((LM_DEBUG
,
893 ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
894 ACE::major_version (),
895 ACE::minor_version(),
896 ACE::beta_version()));
898 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("d:f:q:w:h:c:t:n:"));
908 struct { int c
; int *v
; int (*checkf
)(int); } opts
[] = {
909 { 'd', &dtotal
, validtotal
},
910 { 'f', &ftotal
, validtotal
},
911 { 'q', &qtotal
, validtotal
},
912 { 'w', &wtotal
, validtotal
},
913 { 'h', &htotal
, validtotal
},
914 { 'c', &ctotal
, validtotal
},
915 { 't', &total
, validtotal
},
916 { 'n', &niter
, validiters
},
919 int n
= sizeof(opts
)/sizeof(opts
[0]);
922 while ((opt
= get_opt ()) != EOF
)
926 for (i
= 0; i
< n
; i
++)
928 if (opts
[i
].c
== opt
)
930 int v
= ACE_OS::atoi (get_opt
.opt_arg ());
931 if (!(opts
[i
].checkf
) (v
))
933 usage(ACE_TEXT("CDR_Array_Test"));
944 usage(ACE_TEXT("CDR_Array_Test"));
950 total
= default_total
;
955 niter
= default_niter
;
965 dtotal
= ftotal
= qtotal
= wtotal
= htotal
= ctotal
= total
;
969 for (use_array
= 0; use_array
< 2; use_array
++)
972 CDR_Test
<ACE_CDR::LongLong
, LongLongHelper
>
973 test (qtotal
, niter
, use_array
);
976 CDR_Test
<ACE_CDR::Long
, LongHelper
>
977 test (wtotal
, niter
, use_array
);
980 CDR_Test
<ACE_CDR::Short
, ShortHelper
>
981 test (htotal
, niter
, use_array
);
984 CDR_Test
<ACE_CDR::Char
, CharHelper
>
985 test (ctotal
, niter
, use_array
);
988 CDR_Test
<ACE_CDR::Double
, DoubleHelper
>
989 test (dtotal
, niter
, use_array
);
992 CDR_Test
<ACE_CDR::Float
, FloatHelper
>
993 test (ftotal
, niter
, use_array
);