tracy icon indicating copy to clipboard operation
tracy copied to clipboard

External thread names may be incorrect

Open Lectem opened this issue 7 months ago • 0 comments

I was looking at external thread names for #1105 because I wanted to check if we could(should) do this via ETW instead on windows... and realized that the current code expects threadids (both for the profilee and other applications) to be unique throughout the capture/program lifetime, which is very much not the case on Windows unless your capture is very short. (I think this is fine for your own application as you should not be creating/destroying many threads anyway, but this is an issue for other applications). On linux, it seems to be reused less often, but it can still happen.

#include <vector>
#include <thread>
#include <assert.h>
#include <unordered_set>
#include <iostream>
#ifdef WIN32
#include <windows.h>
#endif

int main(void)
{
    std::unordered_set<std::thread::id> threadIds;
    std::vector<std::thread> threads;

    const size_t nbThreadsPerIteration = 64;

    for (int iters = 0; iters < 1000; iters++)
    {
        for (int i = 0; i < nbThreadsPerIteration; i++)
        {
            threads.emplace_back([] {
                auto stdid = std::this_thread::get_id();
                auto win32id = GetCurrentThreadId();
#ifdef WIN32
                assert(memcmp(&stdid, &win32id, sizeof(win32id)) == 0); // Just to make sure we are indeed using the system thread id and not some internal bookkeeping of the stdlib.
#endif
                });
            if (!threadIds.emplace(threads.back().get_id()).second)
            {
                std::cout << "Duplicate thread id " << threads.back().get_id() << "after " << (iters * nbThreadsPerIteration + i) << "threads created" << std::endl;

                for (auto& thread : threads)
                {
                    thread.detach();
                }
                return 1;
            }
        }
        for (auto& thread : threads)
        {
            thread.join();
        }
        threads.clear();
    }
    return 0;
}

The above program usually stops with a duplicate threadid after about 10k threads on my Win10 machine.

I think the solution might be to have the system provide those names instead (this is already possible on linux since the perf events include the task "comment" (task name). On Windows, we can at least obtain information from the (undocumented, but in manifests) Thread provider opcode 72 SetName.

We should also probably retrieve threads lifetime too. This problem is kind of similar to the issues we can have with shared libraries being unloaded/reloaded, except it probably happens more often on some systems and depends on the programs running on your machine.

Lectem avatar Jul 24 '25 11:07 Lectem