diff --git a/projects/rocprofiler-systems/docs/conceptual/data-collection-modes.rst b/projects/rocprofiler-systems/docs/conceptual/data-collection-modes.rst index bacc4a7b7ae5..98bcaee3e9a9 100644 --- a/projects/rocprofiler-systems/docs/conceptual/data-collection-modes.rst +++ b/projects/rocprofiler-systems/docs/conceptual/data-collection-modes.rst @@ -188,6 +188,8 @@ Additional configuration options to control the tracing behavior include: - ``ROCPROFSYS_TRACE_PERIODS`` (``--trace-periods``): Specifies multiple delay/duration periods in the format ``:``, ``::``, or ``:::``. - ``ROCPROFSYS_TRACE_PERIOD_CLOCK_ID`` (``--trace-clock-id``): Clock type for timing, either ``realtime`` (default) or ``cputime``. +The trace-period clock controls only when collection starts and stops. All CPU and GPU events stored on the trace timeline use ``CLOCK_BOOTTIME``. + Profile mode ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/projects/rocprofiler-systems/source/lib/core/control/CMakeLists.txt b/projects/rocprofiler-systems/source/lib/core/control/CMakeLists.txt index 42976df94231..f40365a7904d 100644 --- a/projects/rocprofiler-systems/source/lib/core/control/CMakeLists.txt +++ b/projects/rocprofiler-systems/source/lib/core/control/CMakeLists.txt @@ -11,6 +11,7 @@ set(control_headers ${CMAKE_CURRENT_LIST_DIR}/clock.hpp ${CMAKE_CURRENT_LIST_DIR}/clocks/posix.hpp ${CMAKE_CURRENT_LIST_DIR}/clocks/steady.hpp + ${CMAKE_CURRENT_LIST_DIR}/clocks/timeline.hpp ${CMAKE_CURRENT_LIST_DIR}/session.hpp ${CMAKE_CURRENT_LIST_DIR}/triggers/roctx.hpp ${CMAKE_CURRENT_LIST_DIR}/triggers/time_window.hpp diff --git a/projects/rocprofiler-systems/source/lib/core/control/clocks/posix.hpp b/projects/rocprofiler-systems/source/lib/core/control/clocks/posix.hpp index 4342c5fa9536..f572597668ef 100644 --- a/projects/rocprofiler-systems/source/lib/core/control/clocks/posix.hpp +++ b/projects/rocprofiler-systems/source/lib/core/control/clocks/posix.hpp @@ -19,6 +19,7 @@ namespace rocprofsys::control::clocks { /// Clock backed by a POSIX clock (clock_gettime / clock_nanosleep). +/// Used for time-window delay/duration sleeps, not absolute event stamps. class posix { public: diff --git a/projects/rocprofiler-systems/source/lib/core/control/clocks/timeline.hpp b/projects/rocprofiler-systems/source/lib/core/control/clocks/timeline.hpp new file mode 100644 index 000000000000..4c17ea173f85 --- /dev/null +++ b/projects/rocprofiler-systems/source/lib/core/control/clocks/timeline.hpp @@ -0,0 +1,40 @@ +// Copyright (c) Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include + +namespace rocprofsys::control::clocks +{ +/// Absolute timeline clock for CPU and call-stack event stamps. +/// Matches the host domain used by rocprofiler-sdk (`CLOCK_BOOTTIME`). +[[nodiscard]] inline bool +timeline_available() noexcept +{ + struct timespec specs = {}; + return clock_gettime(CLOCK_BOOTTIME, &specs) == 0; +} + +[[nodiscard]] inline std::chrono::nanoseconds +timeline_now() noexcept +{ + struct timespec specs = {}; + if(clock_gettime(CLOCK_BOOTTIME, &specs) != 0) + { + return std::chrono::nanoseconds::zero(); + } + return std::chrono::seconds{ specs.tv_sec } + + std::chrono::nanoseconds{ specs.tv_nsec }; +} + +template +[[nodiscard]] inline Tp +timeline_ns() noexcept +{ + return static_cast(timeline_now().count()); +} +} // namespace rocprofsys::control::clocks diff --git a/projects/rocprofiler-systems/source/lib/core/control/tests/CMakeLists.txt b/projects/rocprofiler-systems/source/lib/core/control/tests/CMakeLists.txt index 4e0a7f9aa656..338b00f34a8c 100644 --- a/projects/rocprofiler-systems/source/lib/core/control/tests/CMakeLists.txt +++ b/projects/rocprofiler-systems/source/lib/core/control/tests/CMakeLists.txt @@ -17,6 +17,22 @@ target_include_directories( PRIVATE ${PROJECT_SOURCE_DIR}/source/lib ${CMAKE_BINARY_DIR}/source/lib ) +add_library(control-timeline-clock-tests OBJECT test_timeline.cpp) + +target_link_libraries( + control-timeline-clock-tests + PRIVATE + rocprofiler-systems-googletest-library + rocprofiler-systems-core-library + rocprofiler-systems-common-library + rocprofiler-systems-logger +) + +target_include_directories( + control-timeline-clock-tests + PRIVATE ${PROJECT_SOURCE_DIR}/source/lib ${CMAKE_BINARY_DIR}/source/lib +) + add_library(control-steady-clock-tests OBJECT test_steady_clock.cpp) target_link_libraries( diff --git a/projects/rocprofiler-systems/source/lib/core/control/tests/test_posix_clock.cpp b/projects/rocprofiler-systems/source/lib/core/control/tests/test_posix_clock.cpp index 40f95b0d7192..1746bbf1d849 100644 --- a/projects/rocprofiler-systems/source/lib/core/control/tests/test_posix_clock.cpp +++ b/projects/rocprofiler-systems/source/lib/core/control/tests/test_posix_clock.cpp @@ -6,12 +6,10 @@ #include "core/control/clock.hpp" #include "core/control/triggers/time_window.hpp" -#include - #include #include #include -#include +#include #include namespace diff --git a/projects/rocprofiler-systems/source/lib/core/control/tests/test_timeline.cpp b/projects/rocprofiler-systems/source/lib/core/control/tests/test_timeline.cpp new file mode 100644 index 000000000000..67ed809c221e --- /dev/null +++ b/projects/rocprofiler-systems/source/lib/core/control/tests/test_timeline.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#include "core/control/clocks/timeline.hpp" + +#include +#include +#include +#include + +namespace +{ +using rocprofsys::control::clocks::timeline_available; +using rocprofsys::control::clocks::timeline_now; +using rocprofsys::control::clocks::timeline_ns; + +std::uint64_t +read_boottime_ns() +{ + timespec specs{}; + EXPECT_EQ(clock_gettime(CLOCK_BOOTTIME, &specs), 0); + return static_cast(specs.tv_sec) * std::nano::den + + static_cast(specs.tv_nsec); +} +} // namespace + +TEST(timeline_clock_test, available_on_linux) { EXPECT_TRUE(timeline_available()); } + +TEST(timeline_clock_test, uses_clock_boottime) +{ + ASSERT_TRUE(timeline_available()); + const auto before_duration = read_boottime_ns(); + const auto now_duration = timeline_now(); + const auto after_duration = read_boottime_ns(); + EXPECT_LE(before_duration, static_cast(now_duration.count())); + EXPECT_LE(static_cast(now_duration.count()), after_duration); + + const auto before_ns = read_boottime_ns(); + const auto now_ns = timeline_ns(); + const auto after_ns = read_boottime_ns(); + EXPECT_LE(before_ns, now_ns); + EXPECT_LE(now_ns, after_ns); +} diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library.cpp index d8e169c6f04f..ebdade237974 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library.cpp @@ -24,6 +24,7 @@ #include "core/config/trace_period_config.hpp" #include "core/control/clocks/posix.hpp" #include "core/control/clocks/steady.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/control/session.hpp" #include "core/control/triggers/time_window.hpp" #include "core/cpu.hpp" @@ -1058,7 +1059,7 @@ rocprofsys_init_hidden(const char* _mode, bool _is_binary_rewrite, const char* _ } }); - set_metadata_process_start_timestamp(comp::wall_clock::record()); + set_metadata_process_start_timestamp(control::clocks::timeline_ns()); if(get_debug_env() || get_verbose_env() > 2) { @@ -1129,7 +1130,7 @@ rocprofsys_finalize_hidden(void) return; } - set_metadata_process_end_timestamp(comp::wall_clock::record()); + set_metadata_process_end_timestamp(control::clocks::timeline_ns()); if(_is_child) { @@ -1160,7 +1161,7 @@ rocprofsys_finalize_hidden(void) sampling::block_samples(); - thread_info::set_stop(comp::wall_clock::record()); + thread_info::set_stop(control::clocks::timeline_ns()); tim::signals::block_signals(get_sampling_signals(), tim::signals::sigmask_scope::process); diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/backtrace_timestamp.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/backtrace_timestamp.cpp index c130986845f2..ba9b0c0d0a7b 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/backtrace_timestamp.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/backtrace_timestamp.cpp @@ -2,11 +2,10 @@ // SPDX-License-Identifier: MIT #include "library/components/backtrace_timestamp.hpp" +#include "core/control/clocks/timeline.hpp" #include "library/thread_info.hpp" #include -#include - namespace rocprofsys::component { bool @@ -26,7 +25,7 @@ void backtrace_timestamp::sample(int) { m_tid = tim::threading::get_id(); - m_real = tim::get_clock_real_now(); + m_real = control::clocks::timeline_ns(); } } // namespace rocprofsys::component diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/category_region.hpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/category_region.hpp index f77db8a0d0c8..57b541f9599e 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/category_region.hpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/category_region.hpp @@ -6,6 +6,7 @@ #include "common/defines.h" #include "core/common_types.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/demangler.hpp" #include "core/state.hpp" #include "core/timemory.hpp" @@ -86,10 +87,7 @@ inline constexpr std::size_t renumber_growth_slack = 16; struct wall_clock_source { - timestamp_t now() const - { - return static_cast(rocprofsys::comp::wall_clock::record()); - } + [[nodiscard]] timestamp_t now() const { return control::clocks::timeline_ns(); } }; struct trace_cache_region_sink diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/pthread_create_gotcha.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/pthread_create_gotcha.cpp index d713ab17acd6..44784a29c195 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/pthread_create_gotcha.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/components/pthread_create_gotcha.cpp @@ -3,6 +3,7 @@ #include "library/components/pthread_create_gotcha.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/locking.hpp" #include "core/state.hpp" #include "core/utility.hpp" @@ -221,7 +222,7 @@ pthread_create_gotcha::wrapper::operator()() const { return; } - thread_info::set_stop(comp::wall_clock::record()); + thread_info::set_stop(control::clocks::timeline_ns()); auto& _thr_bundle = thread_bundle_data_t::instance(); if(_thr_bundle && _thr_bundle->get() && _thr_bundle->get()->get_is_running()) diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/kokkosp.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/kokkosp.cpp index bffea142d339..902a140d7dec 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/kokkosp.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/kokkosp.cpp @@ -13,6 +13,7 @@ #include "core/agent_manager.hpp" #include "core/components/fwd.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/node_info.hpp" #include "core/perfetto.hpp" #include "core/trace_cache/cache_manager.hpp" @@ -762,7 +763,7 @@ extern "C" return; } - auto const timestamp = tim::get_clock_real_now(); + auto const timestamp = rocprofsys::control::clocks::timeline_ns(); auto const _thread_state_guard = rocprofsys::state::thread::scoped(rocprofsys::state::thread::Internal); @@ -796,7 +797,7 @@ extern "C" return; } - auto const timestamp = tim::get_clock_real_now(); + auto const timestamp = rocprofsys::control::clocks::timeline_ns(); auto const _thread_state_guard = rocprofsys::state::thread::scoped(rocprofsys::state::thread::Internal); if(rocprofsys::config::get_use_perfetto()) diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/perf.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/perf.cpp index bc3f28812d52..aa69a0337963 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/perf.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/perf.cpp @@ -233,7 +233,7 @@ perf_event::open(double freq, std::uint32_t batch_size, pid_t pid, int cpu) perf_event_a.exclude_callchain_kernel = 1; perf_event_a.use_clockid = 1; // NOLINTNEXTLINE - perf_event_a.clockid = CLOCK_REALTIME; + perf_event_a.clockid = CLOCK_BOOTTIME; return open(perf_event_a, pid, cpu); } diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/pmc/sampler.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/pmc/sampler.cpp index f317a85136a8..618f8885437f 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/pmc/sampler.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/pmc/sampler.cpp @@ -5,6 +5,7 @@ // and ROCPROFSYS_USE_AINIC before any header gates code on that macro. #include "backends/amd_smi/ainic_feature.hpp" +#include "core/control/clocks/timeline.hpp" #include "library/pmc/collectors/common/collector_slice.hpp" #include "library/pmc/collectors/common/settings.hpp" #include "library/pmc/collectors/gpu/cache_policy.hpp" @@ -301,8 +302,7 @@ sample() return; } - auto timestamp = - static_cast(tim::get_clock_real_now()); + auto timestamp = control::clocks::timeline_ns(); for(auto& slice : g_collector_slices) { @@ -405,8 +405,7 @@ post_process() void pause() { - const auto timestamp = - static_cast(tim::get_clock_real_now()); + const auto timestamp = control::clocks::timeline_ns(); // sample() holds this lock for a whole AMD SMI sweep, and the caller is an // application thread leaving a traced region. Hand the timestamp to the diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/sampling.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/sampling.cpp index 61282887e372..12a1cfb030e1 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/sampling.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/sampling.cpp @@ -7,6 +7,7 @@ #include "core/common.hpp" #include "core/components/fwd.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/demangler.hpp" #include "core/locking.hpp" #include "core/node_info.hpp" @@ -795,11 +796,11 @@ configure(bool _setup, std::int64_t _tid) _pe.disabled = 1; _pe.inherit = 0; - if(_pe.type == PERF_TYPE_SOFTWARE) - { - _pe.use_clockid = 1; - _pe.clockid = CLOCK_REALTIME; - } + // Hardware events are the default overflow source. Their sample times + // otherwise stay on perf's CLOCK_MONOTONIC, and parse_overflow_data() + // freezes the monotonic-to-timeline offset from the first sample. + _pe.use_clockid = 1; + _pe.clockid = CLOCK_BOOTTIME; auto _perf_open_error = _perf_sampler->open(_pe, _info->index_data->system_value); @@ -2112,7 +2113,7 @@ pause() } LOG_DEBUG("Pausing sampling..."); - pending_pause_ts.store(tim::get_clock_real_now()); + pending_pause_ts.store(control::clocks::timeline_ns()); block_samples(); set_sampler_timers(timer_state::stopped); } @@ -2130,13 +2131,13 @@ resume() } LOG_DEBUG("Resuming sampling..."); - auto const _pause_ts = pending_pause_ts.exchange(0); - auto const _resume_ts = tim::get_clock_real_now(); - if(_pause_ts > 0) + auto const pause_ts = pending_pause_ts.exchange(0); + auto const resume_ts = control::clocks::timeline_ns(); + if(pause_ts > 0) { auto const _lk = std::lock_guard{ pause_mutex }; pause_intervals.push_back( - pause_interval_t{ .pause_ts = _pause_ts, .resume_ts = _resume_ts }); + pause_interval_t{ .pause_ts = pause_ts, .resume_ts = resume_ts }); } set_sampler_timers(timer_state::running); diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/thread_info.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/thread_info.cpp index 140080e31369..a542bde5f522 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/thread_info.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/thread_info.cpp @@ -5,6 +5,7 @@ #include "core/common.hpp" #include "core/concepts.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/state.hpp" #include "core/utility.hpp" #include "library/causal/delay.hpp" @@ -13,7 +14,6 @@ #include "library/thread_data_growth.hpp" #include -#include #include #include "logger/debug.hpp" @@ -202,7 +202,7 @@ thread_info::init(bool _offset) _info = thread_info{}; _info->is_offset = threading::offset_this_id(); _info->index_data = init_index_data(_tid, _info->is_offset); - _info->lifetime.first = tim::get_clock_real_now(); + _info->lifetime.first = control::clocks::timeline_ns(); const auto _sequent_tid = _info->index_data->sequent_value; _info->causal_count = (!_info->is_offset && _sequent_tid < peak_num_threads) diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.cpp index 3b8cd0401d36..6d0b3dd639f9 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.cpp @@ -5,6 +5,7 @@ #include "common/env_vars.hpp" #include "core/concepts.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/perfetto/emitter.hpp" #include "core/perfetto/engine.hpp" #include "core/state.hpp" @@ -166,7 +167,7 @@ record_thread_start_time() { static thread_local std::once_flag _once{}; std::call_once(_once, []() { - thread_info::set_start(comp::wall_clock::record(), + thread_info::set_start(control::clocks::timeline_ns(), get_mode() != state::process::Mode::sampling); }); } diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.hpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.hpp index 9770ea746d5c..cb5d8a465b9e 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.hpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/tracing.hpp @@ -7,6 +7,7 @@ #include "core/common.hpp" #include "core/concepts.hpp" #include "core/config.hpp" +#include "core/control/clocks/timeline.hpp" #include "core/demangler.hpp" #include "core/perfetto.hpp" #include "core/perfetto/emitter.hpp" @@ -132,7 +133,7 @@ template ROCPROFSYS_INLINE auto now() { - return ::tim::get_clock_real_now(); + return control::clocks::timeline_ns(); } inline auto& diff --git a/projects/rocprofiler-systems/source/tests/CMakeLists.txt b/projects/rocprofiler-systems/source/tests/CMakeLists.txt index 129501108660..c3bd768857f9 100644 --- a/projects/rocprofiler-systems/source/tests/CMakeLists.txt +++ b/projects/rocprofiler-systems/source/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(UNIT_TEST_OBJECTS $ $ $ + $ $ $ $