Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query thread (not process) processor affinity?

On Windows, you can call SetProcessAffinityMask for a process and SetThreadAffinityMask for a thread. However, Windows only appears to expose GetProcessAffinityMask and not a similar API for individual threads of a process.

I have a multi-threaded program that binds individual threads to processors at run-time. As I run it, I'd like to (externally) query which threads are running on which processors to make sure it's working correctly. I've written a small command-line utility to do this. But I can't seem to find a means of finding which processor(s) or core(s) an individual thread is bound to.

This apparently must be possible; I've seen descriptions online of the adplus debugging utility being able to show pstack-like output to show thread affinity. And Process Explorer shows a Threads tab on multi-processor machines that shows the "Ideal Processor" of a thread.

Does anyone know how to query this piece of information?

like image 519
Dan Avatar asked Jul 06 '11 19:07

Dan


People also ask

Why is processor affinity considered when scheduling threads?

Processor affinity takes advantage of the fact that some remnants of a process may remain in one processor's state (in particular, in its cache) from the last time the process ran, and so scheduling it to run on the same processor the next time could result in the process running more efficiently than if it were to run ...

What is processor affinity in SQL Server?

Overview. CPU affinity is the ability to define which processor cores the SQL Server engine will use to multitask. By assigning processor cores SQL Server only uses those processors for multitasking database operations. This can improve performance by reducing processor reloads and thread migration across processors.

What is meant by processor affinity?

Processor affinity is the probability of dispatching of a thread to the processor that was previously executing it. The degree of emphasis on processor affinity should vary directly with the size of the thread's cache working set and inversely with the length of time since it was last dispatched.


2 Answers

You can do it with two calls to SetThreadAffinityMask. This function returns the original affinity mask for the passed thread handle.

So... do one call with a mask that sets affinity to one CPU, and then do a second call to restore the original mask.

Here is complete C/C++ source code including error checking:

DWORD GetThreadAffinityMask(HANDLE thread)
{
    DWORD mask = 1;
    DWORD old = 0;

    // try every CPU one by one until one works or none are left
    while(mask)
    {
        old = SetThreadAffinityMask(thread, mask);
        if(old)
        {   // this one worked
            SetThreadAffinityMask(thread, old); // restore original
            return old;
        }
        else
        {
            if(GetLastError() != ERROR_INVALID_PARAMETER)
                return 0; // fatal error, might as well throw an exception
        }
        mask <<= 1;
    }

    return 0;
}

This code probes one CPU at a time, until setting affinity works (in this case we now know the original mask!) or until the initial 1 has been shifted out of the DWORD. If a CPU is asked that is not available, the function fails with ERROR_INVALID_PARAMETER, and we just try the next one. Usually the first CPU will just work, so it's reasonably efficient.

If the function fails with anything other than ERROR_INVALID_PARAMETER, it means that we either don't have sufficient access rights to the handle, or the system is having some real problems because it can't fulfill our request. Therefore it doesn't make sense to continue in this case.

like image 123
Damon Avatar answered Nov 15 '22 07:11

Damon


Call NtQueryInformationThread, with ThreadBasicInformation:

typedef struct _THREAD_BASIC_INFORMATION
{
    NTSTATUS ExitStatus;
    PTEB TebBaseAddress;
    CLIENT_ID ClientId;
    ULONG_PTR AffinityMask;
    KPRIORITY Priority;
    LONG BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

AFAIK there's no documented way of getting the thread affinity.

like image 24
wj32 Avatar answered Nov 15 '22 07:11

wj32