A Discrete-Event Network Simulator
API
threaded-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Claudio Freire <claudio-daniel.freire@inria.fr>
19  */
20 #include "ns3/test.h"
21 #include "ns3/simulator.h"
22 #include "ns3/list-scheduler.h"
23 #include "ns3/heap-scheduler.h"
24 #include "ns3/map-scheduler.h"
25 #include "ns3/calendar-scheduler.h"
26 #include "ns3/config.h"
27 #include "ns3/string.h"
28 
29 #include <chrono> // seconds, milliseconds
30 #include <ctime>
31 #include <list>
32 #include <thread> // sleep_for
33 #include <utility>
34 
35 using namespace ns3;
36 
38 constexpr int MAXTHREADS = 64;
39 
57 {
58 public:
66  ThreadedSimulatorEventsTestCase (ObjectFactory schedulerFactory, const std::string &simulatorType, unsigned int threads);
71  void EventA (int a);
76  void EventB (int b);
81  void EventC (int c);
86  void EventD (int d);
91  void DoNothing (unsigned int threadno);
96  static void SchedulingThread (std::pair<ThreadedSimulatorEventsTestCase *, unsigned int> context);
100  void End (void);
101  uint64_t m_a;
102  uint64_t m_b;
103  uint64_t m_c;
104  uint64_t m_d;
105  unsigned int m_threads;
106  bool m_threadWaiting[MAXTHREADS];
107  bool m_stop;
109  std::string m_simulatorType;
110  std::string m_error;
111  std::list<std::thread> m_threadlist;
112 
113 private:
114  virtual void DoSetup (void);
115  virtual void DoRun (void);
116  virtual void DoTeardown (void);
117 };
118 
119 ThreadedSimulatorEventsTestCase::ThreadedSimulatorEventsTestCase (ObjectFactory schedulerFactory, const std::string &simulatorType, unsigned int threads)
120  : TestCase ("Check threaded event handling with " +
121  std::to_string (threads) + " threads, " +
122  schedulerFactory.GetTypeId ().GetName () + " scheduler, in " +
123  simulatorType),
124  m_threads (threads),
125  m_schedulerFactory (schedulerFactory),
126  m_simulatorType (simulatorType)
127 {}
128 
129 void
131 {
132  m_stop = true;
133  for (auto& thread : m_threadlist)
134  {
135  if (thread.joinable ())
136  {
137  thread.join ();
138  }
139  }
140 }
141 void
142 ThreadedSimulatorEventsTestCase::SchedulingThread (std::pair<ThreadedSimulatorEventsTestCase *, unsigned int> context)
143 {
144  ThreadedSimulatorEventsTestCase *me = context.first;
145  unsigned int threadno = context.second;
146 
147  while (!me->m_stop)
148  {
149  me->m_threadWaiting[threadno] = true;
150  Simulator::ScheduleWithContext (threadno,
151  MicroSeconds (1),
153  while (!me->m_stop && me->m_threadWaiting[threadno])
154  {
155  std::this_thread::sleep_for (std::chrono::nanoseconds (500));
156  }
157  }
158 }
159 void
161 {
162  if (!m_error.empty ())
163  {
164  m_error = "Bad threaded scheduling";
165  }
166  m_threadWaiting[threadno] = false;
167 }
168 void
170 {
171  if (m_a != m_b || m_a != m_c || m_a != m_d)
172  {
173  m_error = "Bad scheduling";
174  Simulator::Stop ();
175  }
176  ++m_a;
177  Simulator::Schedule (MicroSeconds (10),
179 }
180 
181 void
183 {
184  if (m_a != (m_b + 1) || m_a != (m_c + 1) || m_a != (m_d + 1))
185  {
186  m_error = "Bad scheduling";
187  Simulator::Stop ();
188  }
189  ++m_b;
190  Simulator::Schedule (MicroSeconds (10),
192 }
193 
194 void
196 {
197  if (m_a != m_b || m_a != (m_c + 1) || m_a != (m_d + 1))
198  {
199  m_error = "Bad scheduling";
200  Simulator::Stop ();
201  }
202  ++m_c;
203  Simulator::Schedule (MicroSeconds (10),
205 }
206 
207 void
209 {
210  if (m_a != m_b || m_a != m_c || m_a != (m_d + 1))
211  {
212  m_error = "Bad scheduling";
213  Simulator::Stop ();
214  }
215  ++m_d;
216  if (m_stop)
217  {
218  Simulator::Stop ();
219  }
220  else
221  {
222  Simulator::Schedule (MicroSeconds (10),
224  }
225 }
226 
227 void
229 {
230  if (!m_simulatorType.empty ())
231  {
232  Config::SetGlobal ("SimulatorImplementationType", StringValue (m_simulatorType));
233  }
234 
235  m_error = "";
236 
237  m_a =
238  m_b =
239  m_c =
240  m_d = 0;
241 }
242 void
244 {
245  m_threadlist.clear ();
246 
247  Config::SetGlobal ("SimulatorImplementationType", StringValue ("ns3::DefaultSimulatorImpl"));
248 }
249 void
251 {
252  m_stop = false;
253  Simulator::SetScheduler (m_schedulerFactory);
254 
255  Simulator::Schedule (MicroSeconds (10), &ThreadedSimulatorEventsTestCase::EventA, this, 1);
256  Simulator::Schedule (Seconds (1), &ThreadedSimulatorEventsTestCase::End, this);
257 
258  for (unsigned int i = 0; i < m_threads; ++i)
259  {
260  m_threadlist.push_back (
262  std::pair<ThreadedSimulatorEventsTestCase *, unsigned int> (this,i) ));
263  }
264 
265  Simulator::Run ();
266  Simulator::Destroy ();
267 
268  NS_TEST_EXPECT_MSG_EQ (m_error.empty (), true, m_error.c_str ());
269  NS_TEST_EXPECT_MSG_EQ (m_a, m_b, "Bad scheduling");
270  NS_TEST_EXPECT_MSG_EQ (m_a, m_c, "Bad scheduling");
271  NS_TEST_EXPECT_MSG_EQ (m_a, m_d, "Bad scheduling");
272 }
273 
280 {
281 public:
283  : TestSuite ("threaded-simulator")
284  {
285  std::string simulatorTypes[] = {
286 #ifdef HAVE_RT
287  "ns3::RealtimeSimulatorImpl",
288 #endif
289  "ns3::DefaultSimulatorImpl"
290  };
291  std::string schedulerTypes[] = {
292  "ns3::ListScheduler",
293  "ns3::HeapScheduler",
294  "ns3::MapScheduler",
295  "ns3::CalendarScheduler"
296  };
297  unsigned int threadcounts[] = {
298  0,
299  2,
300  10,
301  20
302  };
303  ObjectFactory factory;
304 
305  for (unsigned int i = 0; i < (sizeof(simulatorTypes) / sizeof(simulatorTypes[0])); ++i)
306  {
307  for (unsigned int j = 0; j < (sizeof(threadcounts) / sizeof(threadcounts[0])); ++j)
308  {
309  for (unsigned int k = 0; k < (sizeof(schedulerTypes) / sizeof(schedulerTypes[0])); ++k)
310  {
311  factory.SetTypeId (schedulerTypes[k]);
312  AddTestCase (new ThreadedSimulatorEventsTestCase (factory, simulatorTypes[i], threadcounts[j]), TestCase::QUICK);
313  }
314  }
315  }
316  }
317 };
318 
Check threaded event handling with various thread number, schedulers, and simulator types.
std::list< std::thread > m_threadlist
Thread list.
static void SchedulingThread(std::pair< ThreadedSimulatorEventsTestCase *, unsigned int > context)
Schedule a thread.
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
ThreadedSimulatorEventsTestCase(ObjectFactory schedulerFactory, const std::string &simulatorType, unsigned int threads)
Constructor.
ObjectFactory m_schedulerFactory
Scheduler factory.
void End(void)
End the thread execution.
bool m_threadWaiting[MAXTHREADS]
Threads waiting to be scheduled.
std::string m_error
Error condition.
uint64_t m_c
The value incremented when EventC is called.
virtual void DoRun(void)
Implementation to actually run this TestCase.
uint64_t m_b
The value incremented when EventB is called.
std::string m_simulatorType
Simulator type.
uint64_t m_d
The value incremented when EventD is called.
unsigned int m_threads
The number of threads.
uint64_t m_a
The value incremented when EventA is called.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
void DoNothing(unsigned int threadno)
No-op function, records the thread that called it.
The threaded simulator Test Suite.
Instantiate subclasses of ns3::Object.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
Hold variables of type string.
Definition: string.h:41
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:891
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1260
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr int MAXTHREADS
Maximum number of threads.
static ThreadedSimulatorTestSuite g_threadedSimulatorTestSuite
Static variable for test initialization.