A Discrete-Event Network Simulator
API
threaded-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Claudio Freire <claudio-daniel.freire@inria.fr>
18  */
19 #include "ns3/calendar-scheduler.h"
20 #include "ns3/config.h"
21 #include "ns3/heap-scheduler.h"
22 #include "ns3/list-scheduler.h"
23 #include "ns3/map-scheduler.h"
24 #include "ns3/simulator.h"
25 #include "ns3/string.h"
26 #include "ns3/test.h"
27 
28 #include <chrono> // seconds, milliseconds
29 #include <ctime>
30 #include <list>
31 #include <thread> // sleep_for
32 #include <utility>
33 
34 using namespace ns3;
35 
37 constexpr int MAXTHREADS = 64;
38 
57 {
58  public:
67  const std::string& simulatorType,
68  unsigned int threads);
73  void EventA(int a);
78  void EventB(int b);
83  void EventC(int c);
88  void EventD(int d);
93  void DoNothing(unsigned int threadno);
98  static void SchedulingThread(std::pair<ThreadedSimulatorEventsTestCase*, unsigned int> context);
102  void End();
103  uint64_t m_a;
104  uint64_t m_b;
105  uint64_t m_c;
106  uint64_t m_d;
107  unsigned int m_threads;
108  bool m_threadWaiting[MAXTHREADS];
109  bool m_stop;
111  std::string m_simulatorType;
112  std::string m_error;
113  std::list<std::thread> m_threadlist;
114 
115  private:
116  void DoSetup() override;
117  void DoRun() override;
118  void DoTeardown() override;
119 };
120 
122  const std::string& simulatorType,
123  unsigned int threads)
124  : TestCase("Check threaded event handling with " + std::to_string(threads) + " threads, " +
125  schedulerFactory.GetTypeId().GetName() + " scheduler, in " + simulatorType),
126  m_threads(threads),
127  m_schedulerFactory(schedulerFactory),
128  m_simulatorType(simulatorType)
129 {
130 }
131 
132 void
134 {
135  m_stop = true;
136  for (auto& thread : m_threadlist)
137  {
138  if (thread.joinable())
139  {
140  thread.join();
141  }
142  }
143 }
144 
145 void
147  std::pair<ThreadedSimulatorEventsTestCase*, unsigned int> context)
148 {
149  ThreadedSimulatorEventsTestCase* me = context.first;
150  unsigned int threadno = context.second;
151 
152  while (!me->m_stop)
153  {
154  me->m_threadWaiting[threadno] = true;
155  Simulator::ScheduleWithContext(threadno,
156  MicroSeconds(1),
158  me,
159  threadno);
160  while (!me->m_stop && me->m_threadWaiting[threadno])
161  {
162  std::this_thread::sleep_for(std::chrono::nanoseconds(500));
163  }
164  }
165 }
166 
167 void
169 {
170  if (!m_error.empty())
171  {
172  m_error = "Bad threaded scheduling";
173  }
174  m_threadWaiting[threadno] = false;
175 }
176 
177 void
179 {
180  if (m_a != m_b || m_a != m_c || m_a != m_d)
181  {
182  m_error = "Bad scheduling";
183  Simulator::Stop();
184  }
185  ++m_a;
186  Simulator::Schedule(MicroSeconds(10), &ThreadedSimulatorEventsTestCase::EventB, this, a + 1);
187 }
188 
189 void
191 {
192  if (m_a != (m_b + 1) || m_a != (m_c + 1) || m_a != (m_d + 1))
193  {
194  m_error = "Bad scheduling";
195  Simulator::Stop();
196  }
197  ++m_b;
198  Simulator::Schedule(MicroSeconds(10), &ThreadedSimulatorEventsTestCase::EventC, this, b + 1);
199 }
200 
201 void
203 {
204  if (m_a != m_b || m_a != (m_c + 1) || m_a != (m_d + 1))
205  {
206  m_error = "Bad scheduling";
207  Simulator::Stop();
208  }
209  ++m_c;
210  Simulator::Schedule(MicroSeconds(10), &ThreadedSimulatorEventsTestCase::EventD, this, c + 1);
211 }
212 
213 void
215 {
216  if (m_a != m_b || m_a != m_c || m_a != (m_d + 1))
217  {
218  m_error = "Bad scheduling";
219  Simulator::Stop();
220  }
221  ++m_d;
222  if (m_stop)
223  {
224  Simulator::Stop();
225  }
226  else
227  {
228  Simulator::Schedule(MicroSeconds(10),
230  this,
231  d + 1);
232  }
233 }
234 
235 void
237 {
238  if (!m_simulatorType.empty())
239  {
240  Config::SetGlobal("SimulatorImplementationType", StringValue(m_simulatorType));
241  }
242 
243  m_error = "";
244 
245  m_a = m_b = m_c = m_d = 0;
246 }
247 
248 void
250 {
251  m_threadlist.clear();
252 
253  Config::SetGlobal("SimulatorImplementationType", StringValue("ns3::DefaultSimulatorImpl"));
254 }
255 
256 void
258 {
259  m_stop = false;
260  Simulator::SetScheduler(m_schedulerFactory);
261 
262  Simulator::Schedule(MicroSeconds(10), &ThreadedSimulatorEventsTestCase::EventA, this, 1);
263  Simulator::Schedule(Seconds(1), &ThreadedSimulatorEventsTestCase::End, this);
264 
265  for (unsigned int i = 0; i < m_threads; ++i)
266  {
267  m_threadlist.emplace_back(
269  std::pair<ThreadedSimulatorEventsTestCase*, unsigned int>(this, i));
270  }
271 
272  Simulator::Run();
273  Simulator::Destroy();
274 
275  NS_TEST_EXPECT_MSG_EQ(m_error.empty(), true, m_error);
276  NS_TEST_EXPECT_MSG_EQ(m_a, m_b, "Bad scheduling");
277  NS_TEST_EXPECT_MSG_EQ(m_a, m_c, "Bad scheduling");
278  NS_TEST_EXPECT_MSG_EQ(m_a, m_d, "Bad scheduling");
279 }
280 
287 {
288  public:
290  : TestSuite("threaded-simulator")
291  {
292  std::string simulatorTypes[] = {
293  "ns3::RealtimeSimulatorImpl",
294  "ns3::DefaultSimulatorImpl",
295  };
296  std::string schedulerTypes[] = {
297  "ns3::ListScheduler",
298  "ns3::HeapScheduler",
299  "ns3::MapScheduler",
300  "ns3::CalendarScheduler",
301  };
302  unsigned int threadCounts[] = {0, 2, 10, 20};
303  ObjectFactory factory;
304 
305  for (auto& simulatorType : simulatorTypes)
306  {
307  for (auto& schedulerType : schedulerTypes)
308  {
309  for (auto& threadCount : threadCounts)
310  {
311  factory.SetTypeId(schedulerType);
312  AddTestCase(
313  new ThreadedSimulatorEventsTestCase(factory, simulatorType, threadCount),
314  TestCase::QUICK);
315  }
316  }
317  }
318  }
319 };
320 
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.
ThreadedSimulatorEventsTestCase(ObjectFactory schedulerFactory, const std::string &simulatorType, unsigned int threads)
Constructor.
ObjectFactory m_schedulerFactory
Scheduler factory.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
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.
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.
void End()
End the thread execution.
void DoRun() override
Implementation to actually run this TestCase.
unsigned int m_threads
The number of threads.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
uint64_t m_a
The value incremented when EventA is called.
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:56
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:936
#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:251
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
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.