From cacb1a25912ada7b47abd17fbc6fb8cff7c00ffe Mon Sep 17 00:00:00 2001 From: Tommaso Bonato Date: Wed, 18 Mar 2026 16:01:37 +0100 Subject: [PATCH] Fix assertion failure in NullEvent::setCompute with small G values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When getGlobalTimeNs() truncates picoseconds to nanoseconds via integer division (now()/1000), converting back to picoseconds (×1000) can produce a value smaller than the actual eventlist().now(). This caused an unsigned underflow in NullEvent::setCompute, scheduling events in the past and triggering 'assert(when >= now())' in EventList::sourceIsPending. The bug surfaces when the LogGOPSim G parameter is small (e.g., 0.0001), because bandwidth_cost2 truncates to 0 for most message sizes, so can_simulate_until stays at the truncated current time rather than advancing into the future. Fixes: 1. null_event.cpp: Guard against underflow by clamping the relative offset to 0 when the target time is at or before now. 2. logsim-interface.cpp (htsim_simulate_until): Clamp the 'until' parameter to at least the current HTSIM time before scheduling. 3. logsim-interface.cpp (OP_SEND): Use std::ceil + std::max(1,...) for bandwidth_cost2 so it never truncates to 0, preventing send pileups that also cause extreme simulation slowdowns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- htsim/sim/logsim-interface.cpp | 10 +++++++++- htsim/sim/null_event.cpp | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/htsim/sim/logsim-interface.cpp b/htsim/sim/logsim-interface.cpp index 81550ad..2484299 100644 --- a/htsim/sim/logsim-interface.cpp +++ b/htsim/sim/logsim-interface.cpp @@ -8,6 +8,8 @@ #include "lgs/TimelineVisualization.hpp" #include "lgs/cmdline.h" #include +#include +#include #include #include #include @@ -222,6 +224,11 @@ void LogSimInterface::htsim_simulate_until(int64_t until) { //printf("Running HTSIM Simulate Until %lu - HtSime Time is %lu\n", until, htsim_api->getGlobalTimeNs()); if (until != -1) { + // Clamp to at least current HTSIM time to avoid scheduling in the past + int64_t htsim_now_ns = static_cast(htsim_api->getGlobalTimeNs()); + if (until < htsim_now_ns) { + until = htsim_now_ns; + } compute_started++; null_events_handler->setCompute(until); } @@ -656,7 +663,8 @@ int start_lgs(std::string filename_goal, LogSimInterface &lgs) { int updated_size = (num_packets+1) * 4160; // Parameterize this. This accounts for the header size elem.size = updated_size; - uint64_t bandwidth_cost2 = static_cast((elem.size) * G); + uint64_t bandwidth_cost2 = std::max(static_cast(1), + static_cast(std::ceil((double)(elem.size) * G))); nextgs[elem.host][elem.nic] = elem.time + g + bandwidth_cost2; can_simulate_until = nextgs[elem.host][elem.nic]; diff --git a/htsim/sim/null_event.cpp b/htsim/sim/null_event.cpp index 4ce1d96..4e79536 100644 --- a/htsim/sim/null_event.cpp +++ b/htsim/sim/null_event.cpp @@ -25,7 +25,12 @@ void NullEvent::doNextEvent() { } void NullEvent::setCompute(simtime_picosec computation_time) { - eventlist().sourceIsPendingRel(*this, computation_time * 1000 - eventlist().now()); // ns to ps + simtime_picosec target_ps = computation_time * 1000; // ns to ps + simtime_picosec now_ps = eventlist().now(); + // Guard against truncation from ns/ps round-trip: if target is at or + // before current time, schedule immediately instead of underflowing. + simtime_picosec rel = (target_ps > now_ps) ? (target_ps - now_ps) : 0; + eventlist().sourceIsPendingRel(*this, rel); } void NullEvent::startComputations() { eventlist().doNextEvent(); }