ns-3 as a SimGrid model
***********************
-The **ns-3 based model** is the most accurate network model in SimGrid. It relies on the well-known
-`ns-3 packet-level network simulator <http://www.nsnam.org>`_ to compute full timing information related to network
-transfers. This
-model is much slower than the LMM-based models. This is because ns-3 simulates the movement of every network packet involved in
-every communication, while the LMM-based models only recompute the respective instantaneous speeds of the currently ongoing
-communications when a communication starts or stops.
+The **ns-3 based model** is the most accurate network model in SimGrid. It relies on the well-known `ns-3 packet-level network
+simulator <http://www.nsnam.org>`_ to compute full timing information related to network transfers. This model is much slower
+than the LMM-based models. This is because ns-3 simulates the movement of every network packet involved in every communication,
+while the LMM-based models only recompute the respective instantaneous speeds of the currently ongoing communications when a
+communication starts or stops. In other terms, both SimGrid and ns-3 are fast and highly optimized, but while SimGrid only
+depends on application-level events (starting and stoping of communications), ns-3 depends on network-level events (sending a
+packet).
You need to install ns-3 and recompile SimGrid accordingly to use this model.
-The SimGrid/ns-3 binding only contains features that are common to both systems. Not all ns-3 models are available from
-SimGrid (only the TCP and WiFi ones are), while not all SimGrid platform files can be used in conjunction with ns-3
-(routes must be of length 1). Note also that the platform built in ns-3 from the SimGrid
-description is very basic. Finally, communicating from a host to
-itself is forbidden in ns-3, so every such communication is simulated to take zero time.
+The SimGrid/ns-3 binding only contains features that are common to both systems. Not all ns-3 models are available from SimGrid
+(only the TCP and WiFi ones are), while not all SimGrid platform files can be used in conjunction with ns-3 (routes must be of
+length 1). Note also that the platform built in ns-3 from the SimGrid description is very basic. Finally, communicating from a
+host to itself is forbidden in ns-3, so every such communication is simulated to take zero time.
+By default, the ns-3 model in SimGrid is not idempotent, unless you patch your version of ns-3 with [this
+patch](https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/1338). It is perfectly OK to have a non-idempotent model in SimGrid as
+long as you only have only one such model, and as long as you don't use utterly advanced things in SimGrid. If you do want to
+have an idempotent ns-3, apply the previously mentioned patch, and recompile SimGrid. It should detect the patch and react
+accordingly.
Compiling the ns-3/SimGrid binding
==================================
/* The boost_stacktrace_backtrace library */
#cmakedefine01 HAVE_BOOST_STACKTRACE_BACKTRACE /* preferred */
#cmakedefine01 HAVE_BOOST_STACKTRACE_ADDR2LINE /* fallback */
+/* Whether the ns-3 library has GetNextEventTime */
+#cmakedefine01 SIMGRID_HAVE_NS3_GetNextEventTime
XBT_DEBUG("Looking for next event in all models");
for (auto model : models_) {
- if (not model->next_occurring_event_is_idempotent()) {
+ if (not model->next_occurring_event_is_idempotent())
continue;
- }
+
double next_event = model->next_occurring_event(now_);
if ((time_delta < 0.0 || next_event < time_delta) && next_event >= 0.0) {
time_delta = next_event;
namespace simgrid {
namespace kernel::resource {
+static bool ns3_is_initialized = false;
NetworkNS3Model::NetworkNS3Model(const std::string& name) : NetworkModel(name)
{
ns3::GlobalRouteManager::DeleteGlobalRoutes(); // just in case this callback is called twice
ns3::GlobalRouteManager::BuildGlobalRoutingDatabase();
ns3::GlobalRouteManager::InitializeRoutes();
+ ns3_is_initialized = true;
});
routing::on_cluster_creation.connect(&clusterCreation_cb);
routing::NetZoneImpl::on_route_creation.connect(&routeCreation_cb);
return new NetworkNS3Action(this, size, src, dst);
}
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+/* If patched, ns3 is idempotent and nice to use */
+bool NetworkNS3Model::next_occurring_event_is_idempotent()
+{
+ return true;
+}
+
+double NetworkNS3Model::next_occurring_event(double sg_time)
+{
+ if (get_started_action_set()->empty()) {
+ return -1.0;
+ }
+
+ double ns3_time = ns3::Simulator::GetNextEventTime().GetSeconds();
+ XBT_DEBUG("NS3 tells that the next occuring event is at %f (it's %f in simgrid), so NS3 returns a delta of %f.",
+ ns3_time, sg_time, ns3_time - sg_time);
+ return ns3_time - sg_time;
+}
+#else
+/* NS3 is only idempotent with the appropriate patch */
+bool NetworkNS3Model::next_occurring_event_is_idempotent()
+{
+ return false;
+}
+
double NetworkNS3Model::next_occurring_event(double now)
{
double time_to_next_flow_completion = 0.0;
return time_to_next_flow_completion;
}
+#endif
void NetworkNS3Model::update_actions_state(double now, double delta)
{
static std::vector<std::string> socket_to_destroy;
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+ /* If the ns-3 model is idempotent, it won't get updated in next_occurring_event() */
+
+ if (not ns3_is_initialized) {
+ XBT_DEBUG("PRESOLVE, I SEE YOU. Don't run ns3 until after all initializations are done.");
+ return;
+ }
+
+ if (delta >= 0) {
+ XBT_DEBUG("DO START simulator delta: %f (current simgrid time: %f; current ns3 time: %f)", delta,
+ simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+ ns3_simulator(delta);
+ } else {
+ XBT_DEBUG("don't start simulator delta: %f (current simgrid time: %f; current ns3 time: %f)", delta,
+ simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+ }
+#endif
+
for (const auto& [ns3_socket, sgFlow] : flow_from_sock) {
NetworkNS3Action* action = sgFlow->action_;
XBT_DEBUG("Processing flow %p (socket %s, action %p)", sgFlow, ns3_socket.c_str(), action);
if (src == dst) {
if (static bool warned = false; not warned) {
XBT_WARN("Sending from a host %s to itself is not supported by ns-3. Every such communication finishes "
- "immediately upon startup.",
+ "immediately upon startup in the SimGrid+ns-3 system.",
src->get_cname());
warned = true;
}
}
} // namespace simgrid
-void ns3_simulator(double maxSeconds)
+void ns3_simulator(double maxSeconds) // maxSecond is a delay, not an absolute time
{
ns3::EventId id;
- if (maxSeconds > 0.0) // If there is a maximum amount of time to run
+ if (maxSeconds >= 0.0) // If there is a maximum amount of time to run
id = ns3::Simulator::Schedule(ns3::Seconds(maxSeconds), &ns3::Simulator::Stop);
- XBT_DEBUG("Start simulator for at most %fs (current time: %f)", maxSeconds, simgrid::kernel::EngineImpl::get_clock());
+ XBT_DEBUG("Start simulator for at most %fs (current simgrid time: %f; current ns3 time: %f)", maxSeconds,
+ simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+ xbt_assert(maxSeconds >= 0.0);
+#endif
ns3::Simulator::Run();
- XBT_DEBUG("Simulator stopped at %fs", ns3::Simulator::Now().GetSeconds());
+ XBT_DEBUG("ns3 simulator stopped at %fs", ns3::Simulator::Now().GetSeconds());
- if (maxSeconds > 0.0)
+ if (maxSeconds >= 0.0)
id.Cancel();
}
StandardLinkImpl* create_wifi_link(const std::string& name, const std::vector<double>& bandwidth) override;
Action* communicate(s4u::Host* src, s4u::Host* dst, double size, double rate, bool streamed) override;
double next_occurring_event(double now) override;
- bool next_occurring_event_is_idempotent() override { return false; }
+ bool next_occurring_event_is_idempotent() override;
void update_actions_state(double now, double delta) override;
};
$ ./ns3-from-src-to-itself ${platfdir}/ns3-big-cluster.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)]%e[%c/%p]%e%m%n"
> [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
-> [:maestro(0)] [res_ns3/WARNING] Sending from a host c-01.rennes to itself is not supported by ns-3. Every such communication finishes immediately upon startup.
+> [:maestro(0)] [res_ns3/WARNING] Sending from a host c-01.rennes to itself is not supported by ns-3. Every such communication finishes immediately upon startup in the SimGrid+ns-3 system.
> [c-01.rennes:receiver(1)] [s4u_test/INFO] Done receiving from 2 senders, each of them sending 5 messages
endforeach()
endif()
+set(SIMGRID_HAVE_NS3_GetNextEventTime FALSE)
if(SIMGRID_HAVE_NS3)
- message(STATUS "ns-3 found (v${NS3_VERSION}; minor:${NS3_MINOR_VERSION}; patch:${NS3_PATCH_VERSION}; libpath: ${NS3_LIBRARY_PATH}).")
+ try_compile(compile_ns3 ${CMAKE_BINARY_DIR} ${CMAKE_HOME_DIRECTORY}/tools/cmake/test_prog/prog_ns3.cpp
+ LINK_LIBRARIES "${NS3_LIBRARIES}"
+ OUTPUT_VARIABLE compile_ns3_output)
+ if(NOT compile_ns3)
+ message(STATUS "ns-3 does not have the ns3::Simulator::GetNextEventTime patch. The ns-3 model will not be idempotent. Compilation output:\n ${compile_ns3_output}")
+ else()
+ set(SIMGRID_HAVE_NS3_GetNextEventTime TRUE)
+ endif()
+ file(REMOVE ${CMAKE_BINARY_DIR}/prog_ns3)
+ message(STATUS "ns-3 found (v${NS3_VERSION}; minor ver:${NS3_MINOR_VERSION}; patch ver:${NS3_PATCH_VERSION}; GetNextEventTime patch: ${SIMGRID_HAVE_NS3_GetNextEventTime}; libpath: ${NS3_LIBRARY_PATH}).")
link_directories(${NS3_LIBRARY_PATH})
include_directories(${NS3_INCLUDE_DIR})
else()
--- /dev/null
+#include "ns3/simulator.h"
+
+int main()
+{
+ ns3::Simulator::GetNextEventTime();
+ return 0;
+}
\ No newline at end of file