rugnux: an NVTX range per timed section and per console step

Every TimingMark ("TIMING <section>") and every rugnux step ("TIMING step ...") now
opens an NVTX v3 range of the same name, so Nsight Systems traces from different
machines can be lined up by pipeline step. Start/end ranges, not push/pop, so a
range may end on another thread and parallel arms may overlap. Header-only NVTX
(CUDA::nvtx3), a no-op without a profiler attached and compiled out without CUDA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 21:49:37 +02:00
co-authored by Claude Opus 5.5
parent f96ee13629
commit fe4db26716
5 changed files with 34 additions and 1 deletions
+3
View File
@@ -43,6 +43,9 @@ ADD_LIBRARY(JFJochLogger STATIC
)
TARGET_LINK_LIBRARIES(JFJochLogger PUBLIC spdlog::spdlog JFJochVersion)
IF (JFJOCH_CUDA_AVAILABLE)
TARGET_LINK_LIBRARIES(JFJochLogger PRIVATE CUDA::nvtx3) # header-only NVTX v3
ENDIF()
ADD_LIBRARY(JFJochZMQ STATIC ZMQWrappers.cpp ZMQWrappers.h)
+18
View File
@@ -9,6 +9,24 @@
#include "Logger.h"
#include "GitInfo.h"
#ifdef JFJOCH_USE_CUDA
#include <nvtx3/nvToolsExt.h>
uint64_t NvtxRangeStart(const std::string &name) {
return nvtxRangeStartA(name.c_str());
}
void NvtxRangeEnd(uint64_t id) {
nvtxRangeEnd(id);
}
#else
uint64_t NvtxRangeStart(const std::string &) {
return 0;
}
void NvtxRangeEnd(uint64_t) {}
#endif
namespace {
spdlog::sink_ptr routed_sink; // set once, at start-up, before any thread logs
}
+10 -1
View File
@@ -70,13 +70,21 @@ public:
void ReplayInto(Logger &to) const;
};
// An NVTX range named `name`, so a timed section shows up by name in an Nsight Systems trace. A start/end
// pair, not a push/pop, so a range may end on another thread and ranges on parallel threads may overlap.
// Without a profiler attached both calls return at once; without CUDA they do nothing.
uint64_t NvtxRangeStart(const std::string &name);
void NvtxRangeEnd(uint64_t id);
// Times one section of a run: logs "TIMING <section> <seconds>" at debug level when the section ends -
// at Stop(), or when the mark goes out of scope, whichever comes first. rugnux keeps debug lines off the
// terminal and in <prefix>_log.txt; tools/rugnux_timing.py turns them into a table.
// terminal and in <prefix>_log.txt; tools/rugnux_timing.py turns them into a table. The section is also
// an NVTX range of the same name.
class TimingMark {
Logger &logger;
std::string section;
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
uint64_t nvtx_range = NvtxRangeStart(section);
bool stopped = false;
public:
TimingMark(Logger &in_logger, std::string in_section)
@@ -88,6 +96,7 @@ public:
if (stopped)
return;
stopped = true;
NvtxRangeEnd(nvtx_range);
logger.Debug("TIMING {} {:.3f}", section,
std::chrono::duration<double>(std::chrono::steady_clock::now() - start).count());
}
+2
View File
@@ -204,6 +204,7 @@ void RugnuxConsole::Close(const char *how) {
}
pending_log_.push_back(std::move(log_text));
pending_timing_.push_back(fmt::format("TIMING step {} {:.3f}", step_title_, total));
NvtxRangeEnd(step_nvtx_);
warnings_held_.clear();
step_ = 0;
}
@@ -216,6 +217,7 @@ void RugnuxConsole::OnStep(const std::string &title) {
step_ = last_step_ = number;
step_title_ = title;
step_start_ = mark_ = Clock::now();
step_nvtx_ = NvtxRangeStart(fmt::format("Step {} {}", step_, title));
notes_ = 0;
if (!verbose_)
Emit(fmt::format("Step {:<2} {}", step_, title));
+1
View File
@@ -74,6 +74,7 @@ private:
int last_step_ = 0;
std::string step_title_;
Clock::time_point step_start_{};
uint64_t step_nvtx_ = 0; // the open step's NVTX range
Clock::time_point mark_{}; // the last line of the open step
int notes_ = 0;