util: shorten thread names to avoid Linux truncation #35173

pull l0rinc wants to merge 2 commits into bitcoin:master from l0rinc:l0rinc/thread-name-truncation changing 10 files +18 −18
  1. l0rinc commented at 4:47 PM on April 28, 2026: contributor

    Problem

    Linux limits thread names set through PR_SET_NAME to 15 visible bytes:

    The name can be up to 16 bytes long, including the terminating null byte.

    Bitcoin Core prefixes system thread names with b-, leaving only 13 bytes for the thread-specific part. This truncates longer indexer names in system tools, for example b-coinstatsindex and b-txospenderindex. It also makes verbose worker suffixes like b-http_pool_N spend much of the available space; the current HTTP worker names fit, but the generic suffix leaves less room for longer pool names.

    The same limit is documented in the existing thread-name helper: https://github.com/bitcoin/bitcoin/blob/8b49e2dd4eed93d08a3d9681d444aaf441ab0037/src/util/threadnames.cpp#L25

    This was noticed during review of #31132 (review)

    Fix

    Shorten the thread names passed to TraceThread while keeping public index identifiers unchanged. ThreadPool workers now uniformly use a dotted numeric suffix, so HTTP workers are named like b-http.0.

    Indexer sync threads now pass display and thread names separately at each BaseIndex call site.

    The current indexer thread names use compact idx-suffixed names that fit within the Linux limit after the b- prefix:

    txindex                  -> txidx
    basic block filter index -> blkfltbscidx
    coinstatsindex           -> coinstatsidx
    txospenderindex          -> txospenderidx
    

    Indexer display names, getindexinfo keys, command-line options, and on-disk index paths are unchanged.

    Testing

    See https://godbolt.org/z/oWonrTKcj for a simple reproducer.

    Alternatively, start bitcoind on Linux with the affected indexes enabled and read the kernel-visible thread names.

    Before this change, the relevant names were truncated or used longer forms:

    b-txindex
    b-basic block f
    b-coinstatsinde
    b-http_pool_15
    b-txospenderind
    

    After this change, the same check shows compact, untruncated names:

    b-txidx
    b-blkfltbscidx
    b-coinstatsidx
    b-http.15
    b-txospenderidx
    
  2. DrahtBot added the label Utils/log/libs on Apr 28, 2026
  3. DrahtBot commented at 4:47 PM on April 28, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35173.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK andrewtoth, hebasto, naiyoma, hodlinator, rkrux

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35206 (doc: fix doxygen links to threads in developer-notes.md by pinheadmz)
    • #34132 (coins: drop error catcher, centralize fatal read handling by l0rinc)
    • #24230 (indexes: Stop using node internal types and locking cs_main, improve sync logic by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. l0rinc force-pushed on Apr 28, 2026
  5. DrahtBot added the label CI failed on Apr 28, 2026
  6. andrewtoth commented at 5:27 PM on April 28, 2026: contributor

    Concept ACK

  7. DrahtBot removed the label CI failed on Apr 28, 2026
  8. hebasto commented at 4:36 PM on April 29, 2026: member

    Before this change, the affected names are truncated or unnecessarily long:

    b-basic block f
    b-coinstatsinde
    b-http_pool_15
    b-txospenderind
    

    After this change, the same check shows compact, untruncated names:

    b-basicfltridx
    b-coinstatsidx
    b-http.15
    b-txospenderidx
    

    Concept ACK.

    b-http_pool_15 fits just fine. Does it really need to be shortened?

  9. l0rinc commented at 4:43 PM on April 29, 2026: contributor

    b-http_pool_15 fits just fine. Does it really need to be shortened?

    The issue is specific to longer pool names. ThreadPool workers get both Bitcoin Core’s b- prefix and the _pool_<n> suffix, so inputfetch_test from #31132 (review) becomes b-inputfetch_test_pool_15. On Linux, that is truncated to b-inputfetch_te, which loses the worker suffix entirely.

  10. naiyoma commented at 5:12 PM on April 30, 2026: contributor

    Concept ACK

  11. in src/index/blockfilterindex.cpp:78 in 9701d1a6bc
      74 | @@ -75,7 +75,7 @@ static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
      75 |  
      76 |  BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
      77 |                                     size_t n_cache_size, bool f_memory, bool f_wipe)
      78 | -    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index")
      79 | +    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index", BlockFilterTypeName(filter_type) + "fltridx")
    


    hodlinator commented at 6:19 PM on April 30, 2026:

    nit: b-basicfltridx should IMO be renamed to include some version of "block".

        : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index", BlockFilterTypeName(filter_type).substr(0, 5) + "blkftrdb")
    

    Giving b-basicblkftrdb (15 chars). Uses "DB" instead of "IDX" which is less accurate but shorter. 😬

    Another strategy could be to consider dropping the b--prefix for Linux or all platforms since figuring out which process a thread belongs to shouldn't be too hard. It appears we already shortened the prefix once in the past though, see 386ae0f6916d11d72022cc6f6b62bb2b82594f24.


    naiyoma commented at 9:44 AM on May 1, 2026:

    b-basicfltridx should IMO be renamed to include some version of "block".

    It seems we have to drop something for it to fit. Maybe these other options might work: blkfltrbasic blkfltrbscidx

    Another strategy could be to consider dropping the b--prefix

    I find the prefix useful, as it makes the threads easily identifiable alongside others.


    hodlinator commented at 11:14 AM on May 1, 2026:

    blkfltrbscidx

    Converting "basic" into "bsc" would require implementing something like StripVowels() or adding another function than BlockFilterTypeName() (BlockFilterCrampedName()). Maybe not strictly necessary.

    Maybe one could change the order to: b-blkfltidx<typename> and just let typename be truncated automatically.

    (I think flt is better abbreviation for "filter", ftr feelds like "footer". Much bikeshedding :grin:).

    I find the prefix useful, as it makes the threads easily identifiable alongside others.

    Yeah, I guess it makes it easier to differentiate our threads from those spawned by libraries we depend on.


    l0rinc commented at 12:22 PM on May 3, 2026:

    Thanks for the comments, changed to blkfltbscidx

  12. hodlinator commented at 6:22 PM on April 30, 2026: contributor

    Concept ACK

  13. l0rinc force-pushed on May 3, 2026
  14. DrahtBot added the label CI failed on May 3, 2026
  15. DrahtBot commented at 10:26 AM on May 3, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task i686, no IPC: https://github.com/bitcoin/bitcoin/actions/runs/25275669316/job/74105141912</sub> <sub>LLM reason (✨ experimental): CI failed because the sock_tests CTest in the “Bitcoin Core Test Suite” failed (ctest reported 6 failures; 1 test failed overall).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  16. l0rinc commented at 12:23 PM on May 3, 2026: contributor

    Thanks for the comments, changed b-txindex/b-basicfltridx to b-txidx/b-blkfltbscidx for consistency. Updated PR description and GodBolt reproducers.

    (The build failure is unrelated)

  17. l0rinc closed this on May 5, 2026

  18. l0rinc reopened this on May 5, 2026

  19. in doc/developer-notes.md:689 in 8924385d37 outdated
     685 | @@ -686,7 +686,7 @@ and its `cs_KeyStore` lock for example).
     686 |  - [ThreadHTTP (`b-http`)](https://doxygen.bitcoincore.org/httpserver_8cpp.html#abb9f6ea8819672bd9a62d3695070709c)
     687 |    : Libevent thread to listen for RPC and REST connections.
     688 |  
     689 | -- [HTTP worker threads (`b-http_pool_x`)](https://doxygen.bitcoincore.org/httpserver_8cpp.html#a2ad0a49dc9b5e8117c0dee98c24187d8)
     690 | +- [HTTP worker threads (`b-http.x`)](https://doxygen.bitcoincore.org/httpserver_8cpp.html#a2ad0a49dc9b5e8117c0dee98c24187d8)
    


    rkrux commented at 9:59 AM on May 5, 2026:

    In 8924385d370068d755a57056c2d3a09f8cd59821 "util: shorten ThreadPool worker names"

    Onboard with the new pool name but it's quite similar to the above http thread that listens for the connections, specially differentiating between b-http and b-http.0 can be confusing for the uninitiated.

    Maybe s/b-http/b-http-server (which is less than 15 chars)? But it might not go with the aim of the PR of shortening the names.


    l0rinc commented at 1:28 PM on May 11, 2026:

    Thanks for taking a look! I don't have a strong preference either way, but I'd lean toward minimal diff here. The .N suffix is a uniform convention for all ThreadPool workers (e.g. PR #31132 introduces b-inputfetch.N for parallel input fetching, and any future pool will likely follow the same pattern). The dot is a deliberate visual cue: any b-<name>.N is a pool worker, anything without a dot is a standalone thread. Special-casing HTTP (either by renaming the listener or by giving its pool a different suffix scheme) would probably weaken that consistent pattern just as it's being established.

    What do other reviewers think?


    rkrux commented at 2:18 PM on May 11, 2026:

    The dot is a deliberate visual cue: any b-<name>.N is a pool worker, anything without a dot is a standalone thread.

    I'm onboard with this new naming for the pool workers because of the truncation issue. While the dot acts as a visual cue, it's not as strong of a cue as the earlier _pool_ was. In order to clearly differentiate the pool threads (http.0 specifically) from the listener thread, this PR can consider updating the bare b-http to b-httplistener or similar - the httplistener portion is the <name>.

    But I should also mention that this is not a strong opinion from my side - will leave it to your preference.


    l0rinc commented at 2:43 PM on May 11, 2026:

    Thanks, I’m leaning toward leaving the listener name unchanged for this PR because the listener itself does not have a truncation problem, and renaming it would widen the scope beyond the ThreadPool worker suffix change. The PR description now calls out the dotted suffix as the uniform worker convention. If you or other reviewers feel strongly about it I don't mind extending the PR.

  20. rkrux commented at 10:08 AM on May 5, 2026: contributor

    Concept ACK 6c2ab6635e1a252540ae8feb7513153b302d426c

    Also, +1 on listing all the indexer threads and keeping their suffixes consistent.

    so inputfetch_test from #31132 (review) becomes b-inputfetch_test_pool_15

    This specific thread name is quite long by itself though and will not fit even after shortening the thread name here. Github is unable to load this comment for me in #31132, but based on a quick glance at the diff I see that the _test is not present.

  21. DrahtBot removed the label CI failed on May 5, 2026
  22. util: shorten ThreadPool worker names
    ThreadPool workers currently format their names as `name_pool_N`.
    Linux truncates the system thread name to 15 visible bytes, so `b-http_pool_N` spends much of that space on the suffix.
    Use a dotted numeric suffix so HTTP worker names become `b-http.N`, leaving more room for longer pool names.
    774cb367dd
  23. in src/index/base.h:145 in 38491a7278
     141 | @@ -141,7 +142,7 @@ class BaseIndex : public CValidationInterface
     142 |      void SetBestBlockIndex(const CBlockIndex* block);
     143 |  
     144 |  public:
     145 | -    BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name);
     146 | +    BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name, const std::string& thread_name = "");
    


    maflcko commented at 1:52 PM on May 11, 2026:

    Is there a value in providing a default here? Is this a leftover from over-splitting the commit? Maybe all of the index commits could be squashed into one?

    Also, I wonder if for the index threads it would be cleaner to use the b-i-$short_name prefix: b-i-tx, b-i-txospender. I presume that devs are familiar with the meaning of i being an index. But just my opinion, not sure what others think.


    rkrux commented at 2:13 PM on May 11, 2026:

    Maybe all of the index commits could be squashed into one?

    I would prefer this.


    l0rinc commented at 2:34 PM on May 11, 2026:

    Is there a value in providing a default here?

    No, not anymore. I made all BaseIndex call sites pass the thread name explicitly.

    Maybe all of the index commits could be squashed into one?

    Agreed. I squashed the indexer thread-name changes into one commit now that the names are explicit instead of being derived incrementally.

    Also, I wonder if for the index threads it would be cleaner to use the b-i-$short_name prefix: b-i-tx, b-i-txospender

    I don't have a strong objection. For now I kept the idx-suffixed names because they fit under the b- limit and already had review support, but happy to switch if reviewers prefer the b-i-* convention.

    Also fixed the stale Doxygen link in doc/developer-notes.md in the latest push and added some clarifying rewording for #35173 (review)


    winterrdog commented at 2:47 PM on May 11, 2026:

    I made all BaseIndex call sites pass the thread name explicitly.

    much better

    For now I kept the idx-suffixed names because they fit under the b- limit

    IMO, the idx-suffixed names are more immediately obvious at a glance than the b-i-* convention.

  24. l0rinc force-pushed on May 11, 2026
  25. index: shorten indexer thread names
    `BaseIndex` currently uses the same name for logs, `getindexinfo`, prune locks, and the sync thread.
    Linux truncates system thread names to 15 visible bytes after the `b-` prefix, so long indexer names are clipped in system tools.
    Pass a separate thread name explicitly at each `BaseIndex` call site and shorten the OS-visible indexer names to `txidx`, `blkfltbscidx`, `coinstatsidx`, and `txospenderidx`.
    The public index names, `getindexinfo` keys, command-line options, and on-disk paths stay unchanged.
    bbe5f03563
  26. l0rinc force-pushed on May 11, 2026
  27. DrahtBot added the label CI failed on May 11, 2026
  28. DrahtBot removed the label CI failed on May 11, 2026
  29. in src/util/threadpool.h:115 in bbe5f03563
     111 | @@ -112,7 +112,7 @@ class ThreadPool
     112 |          // Create workers
     113 |          m_workers.reserve(num_workers);
     114 |          for (int i = 0; i < num_workers; i++) {
     115 | -            m_workers.emplace_back(&util::TraceThread, strprintf("%s_pool_%d", m_name, i), [this] { WorkerThread(); });
     116 | +            m_workers.emplace_back(&util::TraceThread, strprintf("%s.%d", m_name, i), [this] { WorkerThread(); });
    


    hodlinator commented at 6:48 PM on May 19, 2026:

    nanonit: Would prefer prepending 0 to single digits so that thread names sort in order:

                m_workers.emplace_back(&util::TraceThread, strprintf("%s.%02d", m_name, i), [this] { WorkerThread(); });
    

    Same could be done for:

    --- a/src/checkqueue.h
    +++ b/src/checkqueue.h
    @@ -148,7 +148,7 @@ public:
             m_worker_threads.reserve(worker_threads_num);
             for (int n = 0; n < worker_threads_num; ++n) {
                 m_worker_threads.emplace_back([this, n]() {
    -                util::ThreadRename(strprintf("scriptch.%i", n));
    +                util::ThreadRename(strprintf("scriptch.%02i", n));
                     Loop(false /* worker thread */);
                 });
             }
    

    I tried to find places where this actually helped but htop and Sublime Debugger already seem to sort them correctly. Maybe the default is to sort by thread id as a higher priority than names.

  30. in src/index/blockfilterindex.cpp:78 in bbe5f03563
      74 | @@ -75,7 +75,7 @@ static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
      75 |  
      76 |  BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
      77 |                                     size_t n_cache_size, bool f_memory, bool f_wipe)
      78 | -    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index")
      79 | +    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index", "blkfltbscidx")
    


    hodlinator commented at 7:14 PM on May 19, 2026:

    Initializing all BlockFilterIndex with the same thread name is incorrect. Knots has/had a second index to filter transactions based off segwit/non-segwit I think. There's also recently been talk of adding a new index with less compute but higher bandwidth if I recall correctly.

    <details><summary>Possible fix diff</summary>

    diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
    index 44d08440d1..e71b1af401 100644
    --- a/src/blockfilter.cpp
    +++ b/src/blockfilter.cpp
    @@ -19,8 +19,12 @@
     
     using util::Join;
     
    -static const std::map<BlockFilterType, std::string> g_filter_types = {
    -    {BlockFilterType::BASIC, "basic"},
    +struct FilterEntry {
    +    BlockFilterType type;
    +    std::string name;
    +    std::string thread_name;
    +} static constexpr g_filter_types[] = {
    +    {BlockFilterType::BASIC, "basic", "blkfltbscidx"},
     };
     
     uint64_t GCSFilter::HashToRange(const Element& element) const
    @@ -147,16 +151,27 @@ bool GCSFilter::MatchAny(const ElementSet& elements) const
     
     const std::string& BlockFilterTypeName(BlockFilterType filter_type)
     {
    +    for (const auto& entry : g_filter_types) {
    +        if (entry.type == filter_type) return entry.name;
    +    }
    +    static std::string unknown_retval;
    +    return unknown_retval;
    +}
    +
    +const std::string& BlockFilterThreadName(BlockFilterType filter_type)
    +{
    +    for (const auto& entry : g_filter_types) {
    +        if (entry.type == filter_type) return entry.thread_name;
    +    }
         static std::string unknown_retval;
    -    auto it = g_filter_types.find(filter_type);
    -    return it != g_filter_types.end() ? it->second : unknown_retval;
    +    return unknown_retval;
     }
     
     bool BlockFilterTypeByName(std::string_view name, BlockFilterType& filter_type)
     {
         for (const auto& entry : g_filter_types) {
    -        if (entry.second == name) {
    -            filter_type = entry.first;
    +        if (entry.name == name) {
    +            filter_type = entry.type;
                 return true;
             }
         }
    @@ -170,7 +185,7 @@ const std::set<BlockFilterType>& AllBlockFilterTypes()
         static std::once_flag flag;
         std::call_once(flag, []() {
                 for (const auto& entry : g_filter_types) {
    -                types.insert(entry.first);
    +                types.insert(entry.type);
                 }
             });
     
    @@ -179,7 +194,7 @@ const std::set<BlockFilterType>& AllBlockFilterTypes()
     
     const std::string& ListBlockFilterTypes()
     {
    -    static std::string type_list{Join(g_filter_types, ", ", [](const auto& entry) { return entry.second; })};
    +    static std::string type_list{Join(std::span{g_filter_types}, ", ", [](const auto& entry) { return entry.name; })};
     
         return type_list;
     }
    diff --git a/src/blockfilter.h b/src/blockfilter.h
    index 225d3b16be..40d24a725d 100644
    --- a/src/blockfilter.h
    +++ b/src/blockfilter.h
    @@ -99,6 +99,9 @@ enum class BlockFilterType : uint8_t
     /** Get the human-readable name for a filter type. Returns empty string for unknown types. */
     const std::string& BlockFilterTypeName(BlockFilterType filter_type);
     
    +/** Get the short thread name for the filter index thread. */
    +const std::string& BlockFilterThreadName(BlockFilterType filter_type);
    +
     /** Find a filter type by its human-readable name. */
     bool BlockFilterTypeByName(std::string_view name, BlockFilterType& filter_type);
     
    diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
    index 0f69f99902..092889bbaf 100644
    --- a/src/index/blockfilterindex.cpp
    +++ b/src/index/blockfilterindex.cpp
    @@ -75,7 +75,7 @@ static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
     
     BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
                                        size_t n_cache_size, bool f_memory, bool f_wipe)
    -    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index", "blkfltbscidx")
    +    : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index", BlockFilterThreadName(filter_type))
         , m_filter_type(filter_type)
     {
         const std::string& filter_name = BlockFilterTypeName(filter_type);
    

    </details>

  31. hodlinator commented at 7:18 PM on May 19, 2026: contributor

    Reviewed bbe5f03563d3e6c6b5ee3fe4a25a3e3d804bb793


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 06:52 UTC