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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Claudio Freire <claudio-daniel.freire@inria.fr>
7 */
8#include "ns3/calendar-scheduler.h"
9#include "ns3/config.h"
10#include "ns3/heap-scheduler.h"
11#include "ns3/list-scheduler.h"
12#include "ns3/map-scheduler.h"
13#include "ns3/simulator.h"
14#include "ns3/string.h"
15#include "ns3/test.h"
16
17#include <chrono> // seconds, milliseconds
18#include <list>
19#include <thread> // sleep_for
20#include <utility>
21
22using namespace ns3;
23
24/// Maximum number of threads.
25constexpr int MAXTHREADS = 64;
26
27/**
28 * @file
29 * @ingroup threaded-tests
30 * Threaded events test suite
31 */
32
33/**
34 * @ingroup core-tests
35 * @defgroup threaded-tests Threaded events tests
36 */
37
38/**
39 * @ingroup threaded-tests
40 *
41 * @brief Check threaded event handling with various thread number, schedulers, and simulator
42 * types.
43 */
45{
46 public:
47 /**
48 * Constructor.
49 *
50 * @param schedulerFactory The scheduler factory.
51 * @param simulatorType The simulator type.
52 * @param threads The number of threads.
53 */
55 const std::string& simulatorType,
56 unsigned int threads);
57 /**
58 * Event A
59 * @param a The Event parameter.
60 */
61 void EventA(int a);
62 /**
63 * Event B
64 * @param b The Event parameter.
65 */
66 void EventB(int b);
67 /**
68 * Event C
69 * @param c The Event parameter.
70 */
71 void EventC(int c);
72 /**
73 * Event D
74 * @param d The Event parameter.
75 */
76 void EventD(int d);
77 /**
78 * No-op function, records the thread that called it.
79 * @param threadno The thread number.
80 */
81 void DoNothing(unsigned int threadno);
82 /**
83 * Schedule a thread.
84 * @param context The context.
85 */
86 static void SchedulingThread(std::pair<ThreadedSimulatorEventsTestCase*, unsigned int> context);
87 /**
88 * End the thread execution.
89 */
90 void End();
91 uint64_t m_a; //!< The value incremented when EventA is called.
92 uint64_t m_b; //!< The value incremented when EventB is called.
93 uint64_t m_c; //!< The value incremented when EventC is called.
94 uint64_t m_d; //!< The value incremented when EventD is called.
95 unsigned int m_threads; //!< The number of threads.
96 bool m_threadWaiting[MAXTHREADS]; //!< Threads waiting to be scheduled.
97 bool m_stop; //!< Stop variable.
98 ObjectFactory m_schedulerFactory; //!< Scheduler factory.
99 std::string m_simulatorType; //!< Simulator type.
100 std::string m_error; //!< Error condition.
101 std::list<std::thread> m_threadlist; //!< Thread list.
102
103 private:
104 void DoSetup() override;
105 void DoRun() override;
106 void DoTeardown() override;
107};
108
110 const std::string& simulatorType,
111 unsigned int threads)
112 : TestCase("Check threaded event handling with " + std::to_string(threads) + " threads, " +
113 schedulerFactory.GetTypeId().GetName() + " scheduler, in " + simulatorType),
114 m_threads(threads),
115 m_schedulerFactory(schedulerFactory),
116 m_simulatorType(simulatorType)
117{
118}
119
120void
122{
123 m_stop = true;
124 for (auto& thread : m_threadlist)
125 {
126 if (thread.joinable())
127 {
128 thread.join();
129 }
130 }
131}
132
133void
135 std::pair<ThreadedSimulatorEventsTestCase*, unsigned int> context)
136{
137 ThreadedSimulatorEventsTestCase* me = context.first;
138 unsigned int threadno = context.second;
139
140 while (!me->m_stop)
141 {
142 me->m_threadWaiting[threadno] = true;
144 MicroSeconds(1),
146 me,
147 threadno);
148 while (!me->m_stop && me->m_threadWaiting[threadno])
149 {
150 std::this_thread::sleep_for(std::chrono::nanoseconds(500));
151 }
152 }
153}
154
155void
157{
158 if (!m_error.empty())
159 {
160 m_error = "Bad threaded scheduling";
161 }
162 m_threadWaiting[threadno] = false;
163}
164
165void
167{
168 if (m_a != m_b || m_a != m_c || m_a != m_d)
169 {
170 m_error = "Bad scheduling";
172 }
173 ++m_a;
175}
176
177void
179{
180 if (m_a != (m_b + 1) || m_a != (m_c + 1) || m_a != (m_d + 1))
181 {
182 m_error = "Bad scheduling";
184 }
185 ++m_b;
187}
188
189void
191{
192 if (m_a != m_b || m_a != (m_c + 1) || m_a != (m_d + 1))
193 {
194 m_error = "Bad scheduling";
196 }
197 ++m_c;
199}
200
201void
203{
204 if (m_a != m_b || m_a != m_c || m_a != (m_d + 1))
205 {
206 m_error = "Bad scheduling";
208 }
209 ++m_d;
210 if (m_stop)
211 {
213 }
214 else
215 {
218 this,
219 d + 1);
220 }
221}
222
223void
225{
226 if (!m_simulatorType.empty())
227 {
228 Config::SetGlobal("SimulatorImplementationType", StringValue(m_simulatorType));
229 }
230
231 m_error = "";
232
233 m_a = m_b = m_c = m_d = 0;
234}
235
236void
238{
239 m_threadlist.clear();
240
241 Config::SetGlobal("SimulatorImplementationType", StringValue("ns3::DefaultSimulatorImpl"));
242}
243
244void
246{
247 m_stop = false;
249
252
253 for (unsigned int i = 0; i < m_threads; ++i)
254 {
255 m_threadlist.emplace_back(
257 std::pair<ThreadedSimulatorEventsTestCase*, unsigned int>(this, i));
258 }
259
262
263 NS_TEST_EXPECT_MSG_EQ(m_error.empty(), true, m_error);
264 NS_TEST_EXPECT_MSG_EQ(m_a, m_b, "Bad scheduling");
265 NS_TEST_EXPECT_MSG_EQ(m_a, m_c, "Bad scheduling");
266 NS_TEST_EXPECT_MSG_EQ(m_a, m_d, "Bad scheduling");
267}
268
269/**
270 * @ingroup threaded-tests
271 *
272 * @brief The threaded simulator Test Suite.
273 */
275{
276 public:
278 : TestSuite("threaded-simulator")
279 {
280 std::string simulatorTypes[] = {
281 "ns3::RealtimeSimulatorImpl",
282 "ns3::DefaultSimulatorImpl",
283 };
284 std::string schedulerTypes[] = {
285 "ns3::ListScheduler",
286 "ns3::HeapScheduler",
287 "ns3::MapScheduler",
288 "ns3::CalendarScheduler",
289 };
290 unsigned int threadCounts[] = {0, 2, 10, 20};
291 ObjectFactory factory;
292
293 for (auto& simulatorType : simulatorTypes)
294 {
295 for (auto& schedulerType : schedulerTypes)
296 {
297 for (auto& threadCount : threadCounts)
298 {
299 factory.SetTypeId(schedulerType);
301 new ThreadedSimulatorEventsTestCase(factory, simulatorType, threadCount),
303 }
304 }
305 }
306 }
307};
308
309/// 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:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition simulator.h:597
static void Run()
Run the simulation.
Definition simulator.cc:161
static void SetScheduler(ObjectFactory schedulerFactory)
Set the scheduler type with an ObjectFactory.
Definition simulator.cc:147
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
std::string GetName() const
Definition test.cc:371
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
void SetGlobal(std::string name, const AttributeValue &value)
Definition config.cc:932
#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:1415
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
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.