Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / ACE / tests / Token_Strategy_Test.cpp
blobae53a319d69b3b153288c39446f03d422f6e7e61
1 // ============================================================================
2 //
3 // = LIBRARY
4 // tests
5 //
6 // = DESCRIPTION
7 // This program tests the behavior of ACE_Token under a variety of scenarios
8 // in order verify whether or not tokens are returned, and threads run, in
9 // a LIFO or FIFO manner.
11 // = AUTHOR
12 // Don Hinton <dhinton@ieee.org>
14 // ============================================================================
16 #include "test_config.h"
17 #include "ace/Token.h"
18 #include "ace/Task.h"
19 #include "ace/Atomic_Op.h"
20 #include "ace/Auto_IncDec_T.h"
21 #include "ace/Vector_T.h"
22 #include "ace/Stats.h"
23 #include "ace/ACE.h"
24 #include "ace/Barrier.h"
28 #if defined (ACE_HAS_THREADS)
30 class Token_Strategy_Test : public ACE_Task<ACE_MT_SYNCH>
32 public:
34 Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy = ACE_Token::FIFO,
35 int threads = 5, int invocations = 10);
36 ~Token_Strategy_Test (void);
38 //FUZZ: disable check_for_lack_ACE_OS
39 int open (void *a = 0);
40 //FUZZ: enable check_for_lack_ACE_OS
42 int svc (void);
44 private:
45 // Number of threads for the test, must be 5 or more.
46 int threads_;
48 // Barrier used to try to synchronize the for loop in the svc() method.
49 ACE_Barrier barrier_;
51 // Token used to synchonize for loop.
52 ACE_Token token_;
54 // Token strategy to use, LIFO/FIFO.
55 ACE_Token::QUEUEING_STRATEGY strategy_;
57 // Number of loops.
58 int invocations_;
60 // Vector of token counts, one per thread.
61 ACE_Vector<ACE_INT32> vec_token_count_;
63 // This keeps a count of the number of threads who have the token--should always
64 // be 0 or 1;
65 ACE_Atomic_Op<ACE_Thread_Mutex, int> counter_;
67 // Number of active threads in svc() method.
68 ACE_Atomic_Op<ACE_Thread_Mutex, int> active_;
70 // Errors count, set in svc() and returned from open().
71 ACE_Atomic_Op<ACE_Thread_Mutex, int> errors_;
73 ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test (const Token_Strategy_Test &))
74 ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test &operator= (const Token_Strategy_Test &))
78 Token_Strategy_Test::Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy, int threads, int invocations)
79 : threads_ (threads < 5 ? 5 : threads), // need at least 5 threads to satisfy test conditions.
80 barrier_ (threads_),
81 strategy_ (strategy),
82 invocations_ (invocations < 10 ? 10 : invocations), // insure we loop at least a few times.
83 vec_token_count_ (threads_)
85 this->counter_ = 0;
86 this->active_ = 0;
87 this->errors_ = 0;
89 // Initialize the per thread counters used for generating stats.
90 for (int i = 0; i < this->threads_; ++i)
92 const ACE_UINT32 sample = 0;
93 this->vec_token_count_.push_back (sample);
96 this->token_.queueing_strategy (this->strategy_);
98 ACE_DEBUG ((LM_DEBUG,
99 ACE_TEXT (" (tid = %t) Token_Test::Token_Test (\n")
100 ACE_TEXT (" token_type = %s\n")
101 ACE_TEXT (" thread = %d\n")
102 ACE_TEXT (" invocations = %d\n"),
103 this->strategy_ == ACE_Token::FIFO ? ACE_TEXT ("FIFO") : ACE_TEXT ("LIFO"),
104 this->threads_,
105 this->invocations_));
108 Token_Strategy_Test::~Token_Strategy_Test (void)
112 Token_Strategy_Test::open (void *)
114 // spawn threads in ace task...
115 // Make this Task into an Active Object.
116 this->activate (THR_BOUND | THR_DETACHED, this->threads_);
118 // Wait for all the threads to exit.
119 this->thr_mgr ()->wait ();
120 return this->errors_.value ();
124 Token_Strategy_Test::svc (void)
126 int current = this->active_.value ();
127 ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > active_counter (this->active_);
128 this->barrier_.wait ();
131 //ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (tid = %t) starting loop\n")));
132 for (int i = 0; i < this->invocations_; i++)
134 ACE_GUARD_RETURN (ACE_Token, lock, this->token_, -1);
135 this->vec_token_count_[current]++;
136 ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > token_count_counter (this->counter_);
138 // Turn this on to watch each thread grab the token. LIFO has the interesting
139 // behavior that two thread seem to take turns while all the other threads wait.
140 if (0)
141 ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (tid = %t) token count = %d, ")
142 ACE_TEXT ("waiters = %d, loop: %d/%d\n"),
143 this->counter_.value (),
144 this->token_.waiters (), i + 1,
145 this->invocations_));
147 // Yield, then simulate some work in order to give the other threads a chance to queue up.
148 ACE_Thread::yield ();
149 for (int k = 0; k != 100; ++k)
151 ACE::is_prime (k, 2, k/2);
154 // If we are the first thread to finish, compute the stats.
155 if (i + 1 == this->invocations_)
157 if (this->active_ == this->threads_)
159 ACE_Stats stats;
160 ACE_Stats_Value std_dev (2);
161 ACE_Stats_Value mean (2);
162 for (int i = 0; i < this->threads_; ++i)
164 stats.sample (this->vec_token_count_[i]);
167 //stats.print_summary (2);
168 stats.std_dev (std_dev);
169 stats.mean (mean);
170 ACE_DEBUG ((LM_DEBUG,
171 ACE_TEXT (" (tid = %t) mean = %d.%d, std_dev = %d.%d, max = %d, min = %d\n"),
172 mean.whole (), mean.fractional (), std_dev.whole (), std_dev.fractional (),
173 stats.max_value (), stats.min_value ()));
175 // These are pretty simplistic tests, so let me know if you have a better idea.
176 // The assumption is that the standard deviation will be small when using the
177 // FIFO strategy since all threads will share the token more or less evenly.
178 // In contrast, the LIFO strategy will allow the two threads to alternate, thus
179 // several threads will have a low, or zero, token count and create a low mean and
180 // high standard deviation. If the the thread count is over say 4 or 5, the
181 // standard deviation will actually excide the mean, hence the test.
182 if (this->strategy_ == ACE_Token::LIFO &&
183 (mean.whole () > std_dev.whole () &&
184 mean.fractional () > std_dev.fractional ()))
186 ACE_DEBUG ((LM_ERROR,
187 ACE_TEXT (" (tid = %t) LIFO: mean greater than std_dev.\n")));
188 this->errors_++;
190 if (this->strategy_ == ACE_Token::FIFO &&
191 (mean.whole () < std_dev.whole () &&
192 mean.fractional () < std_dev.fractional ()))
194 ACE_DEBUG ((LM_ERROR,
195 ACE_TEXT (" (tid = %t) FIFO: mean less than std_dev.\n")));
196 this->errors_++;
201 return 0;
205 int run_test (ACE_Token::QUEUEING_STRATEGY strategy, int threads = 5,
206 int invocations = 10)
208 Token_Strategy_Test test (strategy, threads, invocations);
209 return test.open () == 0 ? 0 : 1;
213 run_main (int argc, ACE_TCHAR *argv[])
215 ACE_START_TEST (ACE_TEXT ("Token_Strategy_Test"));
216 int retval = 0;
218 if (argc > 3)
220 // print usage
221 retval = 1;
223 else
225 int threads = 5;
226 int invocations = 100;
228 if (argc > 1) threads = ACE_OS::atoi (argv[1]);
229 if (argc > 2) invocations = ACE_OS::atoi (argv[2]);
231 // New test using ACE_Token::queueing_strategy ()
232 retval += run_test (ACE_Token::FIFO, threads, invocations);
233 retval += run_test (ACE_Token::LIFO, threads, invocations);
236 ACE_END_TEST;
237 return retval;
240 #else /* ACE_HAS_THREADS */
242 run_main (int, ACE_TCHAR *[])
244 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Token_Strategy_Test: your platform doesn't support threads\n")), 1);
246 #endif /* ACE_HAS_THREADS */