From 7427ab545f1c2efb9e361ca15e56c222fdf9e4e1 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 22 Jul 2026 21:06:58 +0000 Subject: [PATCH 1/3] Name KvikIO thread-pool worker threads for profiling BS::thread_pool accepts an init_task that runs once on each worker thread as it starts. Use it to set the OS thread name (comm on Linux) via pthread_setname_np, so KvikIO's IO workers show up in nsys, py-spy, top -H, and /proc//task//comm as 'kvikio-' (global default pool) or 'kvikio-dev-' (per-block-device pools) instead of the generic parent process name. Add a make_thread_pool_init_task(prefix) helper in threadpool_wrapper.hpp that captures a shared atomic counter, so threads within a pool get sequential indices and different pools sharing the same prefix do not collide. POSIX only (pthread_setname_np); a no-op elsewhere. Names fit Linux's 15-char comm limit: 'kvikio-' up to 4-digit idx = 11 chars, 'kvikio-dev-' up to 3-digit idx = 14 chars. --- cpp/include/kvikio/defaults.hpp | 2 +- cpp/include/kvikio/threadpool_wrapper.hpp | 51 ++++++++++++++++++++++- cpp/src/defaults.cpp | 3 +- cpp/src/file_handle.cpp | 3 +- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/cpp/include/kvikio/defaults.hpp b/cpp/include/kvikio/defaults.hpp index 53f97599f9..141ae50303 100644 --- a/cpp/include/kvikio/defaults.hpp +++ b/cpp/include/kvikio/defaults.hpp @@ -121,7 +121,7 @@ std::tuple getenv_or( */ class defaults { private: - ThreadPool _thread_pool{get_num_threads_from_env()}; + ThreadPool _thread_pool{get_num_threads_from_env(), make_thread_pool_init_task("kvikio")}; CompatMode _compat_mode; std::size_t _task_size; std::size_t _gds_threshold; diff --git a/cpp/include/kvikio/threadpool_wrapper.hpp b/cpp/include/kvikio/threadpool_wrapper.hpp index d0e8d4b286..194770834d 100644 --- a/cpp/include/kvikio/threadpool_wrapper.hpp +++ b/cpp/include/kvikio/threadpool_wrapper.hpp @@ -1,12 +1,22 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include +#include +#include +#include +#include + #include +#if defined(__linux__) || defined(__APPLE__) +#include +#endif + namespace kvikio { /** @@ -14,4 +24,43 @@ namespace kvikio { */ using ThreadPool = BS::thread_pool; +/** + * @brief Build a `BS::thread_pool` init task that names each worker thread. + * + * The returned functor is intended to be passed to `BS::thread_pool`'s + * constructor or `reset()` overloads that accept an `init_task`. It runs + * once per worker as the pool starts each thread, setting the OS-level + * thread name (`comm` on Linux) to `"-"` so profilers such + * as nsys, `top -H`, and `/proc//task//comm` show meaningful + * names instead of the parent process name. + * + * The per-thread index is assigned via an atomic counter captured by the + * returned functor, so different pools can share the same prefix without + * colliding. + * + * On platforms that do not provide `pthread_setname_np`, this is a no-op. + * + * Linux caps thread names at 15 characters plus NUL, so keep @p prefix + * short (typically 10 characters or fewer). + * + * @param prefix Name prefix, e.g. `"kvikio"` or `"kvikio-dev"`. + * @return An init task suitable for `BS::thread_pool`. + */ +[[nodiscard]] inline std::function make_thread_pool_init_task(std::string prefix) +{ + auto counter = std::make_shared>(0); + return [counter = std::move(counter), prefix = std::move(prefix)]() { +#if defined(__linux__) || defined(__APPLE__) + unsigned int const idx = counter->fetch_add(1, std::memory_order_relaxed); + char name[16] = {}; // Linux comm limit is 15 chars + NUL. + std::snprintf(name, sizeof(name), "%s-%u", prefix.c_str(), idx); +#if defined(__linux__) + pthread_setname_np(pthread_self(), name); +#else // __APPLE__: only names the calling thread and takes no pthread_t. + pthread_setname_np(name); +#endif +#endif + }; +} + } // namespace kvikio diff --git a/cpp/src/defaults.cpp b/cpp/src/defaults.cpp index fdcaf0d746..11cefba2e6 100644 --- a/cpp/src/defaults.cpp +++ b/cpp/src/defaults.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace kvikio { @@ -220,7 +221,7 @@ void defaults::set_thread_pool_nthreads(unsigned int nthreads) { KVIKIO_EXPECT( nthreads > 0, "number of threads must be a positive integer", std::invalid_argument); - thread_pool().reset(nthreads); + thread_pool().reset(nthreads, make_thread_pool_init_task("kvikio")); } unsigned int defaults::num_threads() { return thread_pool_nthreads(); } diff --git a/cpp/src/file_handle.cpp b/cpp/src/file_handle.cpp index f058276fe2..6807af925d 100644 --- a/cpp/src/file_handle.cpp +++ b/cpp/src/file_handle.cpp @@ -80,7 +80,8 @@ ThreadPool* get_thread_pool_per_block_device(std::string const& file_path) } // First file on this block device: create a new dedicated thread pool - auto thread_pool = std::make_shared(defaults::num_threads()); + auto thread_pool = std::make_shared( + defaults::num_threads(), make_thread_pool_init_task("kvikio-dev")); dev_id_to_thread_pool_map.emplace(block_dev_info.id, thread_pool); file_path_to_thread_pool_map.emplace(file_path, thread_pool); return thread_pool.get(); From 5a5dd3461b740a4255d6fdddf3882d9cb78b9cc3 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 22 Jul 2026 22:51:19 +0000 Subject: [PATCH 2/3] Drop non-Linux guards from thread-naming helper KvikIO only supports Linux, so the '#if defined(__linux__) || defined(__APPLE__)' guards and the macOS pthread_setname_np branch in make_thread_pool_init_task added noise without ever being compiled. Remove them and let be included unconditionally, along with the docstring line about non-POSIX platforms. --- cpp/include/kvikio/threadpool_wrapper.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cpp/include/kvikio/threadpool_wrapper.hpp b/cpp/include/kvikio/threadpool_wrapper.hpp index 194770834d..7e13b88235 100644 --- a/cpp/include/kvikio/threadpool_wrapper.hpp +++ b/cpp/include/kvikio/threadpool_wrapper.hpp @@ -13,9 +13,7 @@ #include -#if defined(__linux__) || defined(__APPLE__) #include -#endif namespace kvikio { @@ -38,8 +36,6 @@ using ThreadPool = BS::thread_pool; * returned functor, so different pools can share the same prefix without * colliding. * - * On platforms that do not provide `pthread_setname_np`, this is a no-op. - * * Linux caps thread names at 15 characters plus NUL, so keep @p prefix * short (typically 10 characters or fewer). * @@ -50,16 +46,10 @@ using ThreadPool = BS::thread_pool; { auto counter = std::make_shared>(0); return [counter = std::move(counter), prefix = std::move(prefix)]() { -#if defined(__linux__) || defined(__APPLE__) unsigned int const idx = counter->fetch_add(1, std::memory_order_relaxed); char name[16] = {}; // Linux comm limit is 15 chars + NUL. std::snprintf(name, sizeof(name), "%s-%u", prefix.c_str(), idx); -#if defined(__linux__) pthread_setname_np(pthread_self(), name); -#else // __APPLE__: only names the calling thread and takes no pthread_t. - pthread_setname_np(name); -#endif -#endif }; } From 3f5f08475cf9a1f9336e6965d6bbabcced347a9f Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 23 Jul 2026 01:12:08 +0000 Subject: [PATCH 3/3] Fix style --- cpp/include/kvikio/defaults.hpp | 2 +- cpp/include/kvikio/threadpool_wrapper.hpp | 8 +++++--- cpp/src/defaults.cpp | 2 +- cpp/src/file_handle.cpp | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cpp/include/kvikio/defaults.hpp b/cpp/include/kvikio/defaults.hpp index 141ae50303..62eaa5722d 100644 --- a/cpp/include/kvikio/defaults.hpp +++ b/cpp/include/kvikio/defaults.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/cpp/include/kvikio/threadpool_wrapper.hpp b/cpp/include/kvikio/threadpool_wrapper.hpp index 7e13b88235..b036c419e4 100644 --- a/cpp/include/kvikio/threadpool_wrapper.hpp +++ b/cpp/include/kvikio/threadpool_wrapper.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include @@ -47,9 +48,10 @@ using ThreadPool = BS::thread_pool; auto counter = std::make_shared>(0); return [counter = std::move(counter), prefix = std::move(prefix)]() { unsigned int const idx = counter->fetch_add(1, std::memory_order_relaxed); - char name[16] = {}; // Linux comm limit is 15 chars + NUL. - std::snprintf(name, sizeof(name), "%s-%u", prefix.c_str(), idx); - pthread_setname_np(pthread_self(), name); + // Linux comm limit is 15 chars + NUL. + std::array name{}; + std::snprintf(name.data(), name.size(), "%s-%u", prefix.c_str(), idx); + pthread_setname_np(pthread_self(), name.data()); }; } diff --git a/cpp/src/defaults.cpp b/cpp/src/defaults.cpp index 11cefba2e6..6b27f12ccc 100644 --- a/cpp/src/defaults.cpp +++ b/cpp/src/defaults.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/cpp/src/file_handle.cpp b/cpp/src/file_handle.cpp index 6807af925d..edd5b7b7dd 100644 --- a/cpp/src/file_handle.cpp +++ b/cpp/src/file_handle.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -80,8 +80,8 @@ ThreadPool* get_thread_pool_per_block_device(std::string const& file_path) } // First file on this block device: create a new dedicated thread pool - auto thread_pool = std::make_shared( - defaults::num_threads(), make_thread_pool_init_task("kvikio-dev")); + auto thread_pool = std::make_shared(defaults::num_threads(), + make_thread_pool_init_task("kvikio-dev")); dev_id_to_thread_pool_map.emplace(block_dev_info.id, thread_pool); file_path_to_thread_pool_map.emplace(file_path, thread_pool); return thread_pool.get();