A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
34using namespace ns3;
35
36/// Maximum number of threads.
37constexpr int MAXTHREADS = 64;
38
39/**
40 * \file
41 * \ingroup threaded-tests
42 * Threaded events test suite
43 */
44
45/**
46 * \ingroup core-tests
47 * \defgroup threaded-tests Threaded events tests
48 */
49
50/**
51 * \ingroup threaded-tests
52 *
53 * \brief Check threaded event handling with various thread number, schedulers, and simulator
54 * types.
55 */
57{
58 public:
59 /**
60 * Constructor.
61 *
62 * \param schedulerFactory The scheduler factory.
63 * \param simulatorType The simulator type.
64 * \param threads The number of threads.
65 */
67 const std::string& simulatorType,
68 unsigned int threads);
69 /**
70 * Event A
71 * \param a The Event parameter.
72 */
73 void EventA(int a);
74 /**
75 * Event B
76 * \param b The Event parameter.
77 */
78 void EventB(int b);
79 /**
80 * Event C
81 * \param c The Event parameter.
82 */
83 void EventC(int c);
84 /**
85 * Event D
86 * \param d The Event parameter.
87 */
88 void EventD(int d);
89 /**
90 * No-op function, records the thread that called it.
91 * \param threadno The thread number.
92 */
93 void DoNothing(unsigned int threadno);
94 /**
95 * Schedule a thread.
96 * \param context The context.
97 */
98 static void SchedulingThread(std::pair<ThreadedSimulatorEventsTestCase*, unsigned int> context);
99 /**
100 * End the thread execution.
101 */
102 void End();
103 uint64_t m_a; //!< The value incremented when EventA is called.
104 uint64_t m_b; //!< The value incremented when EventB is called.
105 uint64_t m_c; //!< The value incremented when EventC is called.
106 uint64_t m_d; //!< The value incremented when EventD is called.
107 unsigned int m_threads; //!< The number of threads.
108 bool m_threadWaiting[MAXTHREADS]; //!< Threads waiting to be scheduled.
109 bool m_stop; //!< Stop variable.
110 ObjectFactory m_schedulerFactory; //!< Scheduler factory.
111 std::string m_simulatorType; //!< Simulator type.
112 std::string m_error; //!< Error condition.
113 std::list<std::thread> m_threadlist; //!< Thread list.
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
132void
134{
135 m_stop = true;
136 for (auto& thread : m_threadlist)
137 {
138 if (thread.joinable())
139 {
140 thread.join();
141 }
142 }
143}
144
145void
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;
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
167void
169{
170 if (!m_error.empty())
171 {
172 m_error = "Bad threaded scheduling";
173 }
174 m_threadWaiting[threadno] = false;
175}
176
177void
179{
180 if (m_a != m_b || m_a != m_c || m_a != m_d)
181 {
182 m_error = "Bad scheduling";
184 }
185 ++m_a;
187}
188
189void
191{
192 if (m_a != (m_b + 1) || m_a != (m_c + 1) || m_a != (m_d + 1))
193 {
194 m_error = "Bad scheduling";
196 }
197 ++m_b;
199}
200
201void
203{
204 if (m_a != m_b || m_a != (m_c + 1) || m_a != (m_d + 1))
205 {
206 m_error = "Bad scheduling";
208 }
209 ++m_c;
211}
212
213void
215{
216 if (m_a != m_b || m_a != m_c || m_a != (m_d + 1))
217 {
218 m_error = "Bad scheduling";
220 }
221 ++m_d;
222 if (m_stop)
223 {
225 }
226 else
227 {
230 this,
231 d + 1);
232 }
233}
234
235void
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
248void
250{
251 m_threadlist.clear();
252
253 Config::SetGlobal("SimulatorImplementationType", StringValue("ns3::DefaultSimulatorImpl"));
254}
255
256void
258{
259 m_stop = false;
261
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
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
281/**
282 * \ingroup threaded-tests
283 *
284 * \brief The threaded simulator Test Suite.
285 */
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);
313 new ThreadedSimulatorEventsTestCase(factory, simulatorType, threadCount),
314 TestCase::Duration::QUICK);
315 }
316 }
317 }
318 }
319};
320
321/// Static variable for test initialization.
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.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:588
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void SetScheduler(ObjectFactory schedulerFactory)
Set the scheduler type with an ObjectFactory.
Definition: simulator.cc:164
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:940
#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:252
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Every class exported by the ns3 library is enclosed in the ns3 namespace.
STL namespace.
constexpr int MAXTHREADS
Maximum number of threads.
static ThreadedSimulatorTestSuite g_threadedSimulatorTestSuite
Static variable for test initialization.