# Should we be using "scheduler\_affinity" for default number of threads?

**URL:** https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278
**Category:** Uncategorized
**Created:** [October 23, 2024, 3:35pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278 "2024-10-23T15:35:32Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)
#### Post date: [October 23, 2024, 3:35pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/1 "2024-10-23T15:35:32Z")

</div>

The current way to get the default number of threads ( if not envs are set) is to look at the hardware:

> <https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/src/itkMultiThreaderBase.cxx#L335-L374>

This has not been a good default when ITK is used in a docker container ( where the default become the number of cores on the physical system, and not what is allocated to the container), and with certain distributed clustering environments where only a certain number of core/processors are allocated to the task. The latter was supported with some scheduler with support for “NSLOTS” environment variable.

Looking into this issue from Python I found the following:

> <https://stackoverflow.com/questions/64189176/os-sched-getaffinity0-vs-os-cpu-count>

This scheduler affinity seems to work for both docker images and my scheduler. There is a corresponding C method for unix:  
[https://linux.die.net/man/2/sched\_getaffinity](https://linux.die.net/man/2/sched_getaffinity)  
or  
[https://linux.die.net/man/3/pthread\_getaffinity\_np](https://linux.die.net/man/3/pthread_getaffinity_np)

Anyone familiar with these?

I have not checked how TBB behaves with these two problematic situations.

---

<div class="post-metadata">

### Author: ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)
#### Post date: [October 23, 2024, 3:50pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/2 "2024-10-23T15:50:51Z")

</div>

I am fine with this change, as long as it works across multiple platforms. A Windows equivalent might be [GetProcessAffinityMask()](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask). Also possibly relevant is [GetSystemInfo()](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo). [This discussion](https://stackoverflow.com/questions/76317127/windows-11-thread-affinities-spanning-multiple-processor-groups-explicitly) might be relevant too, if someone is looking into implementing it.

---

<div class="post-metadata">

### Author: ![seanm](https://discourse.itk.org/letter_avatar_proxy/v4/letter/s/a88e4f/32.png) [@seanm](https://discourse.itk.org/u/seanm)
#### Post date: [October 23, 2024, 4:06pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/3 "2024-10-23T16:06:36Z")

</div>

The `np` in `pthread_getaffinity_np` means ‘non portable’ and indeed this function does not seem to exist on the BSDs, including macOS.

But anyway, thread affinity seems orthogonal to what you’re talking about, which is the number of threads available for use by ITK.

(Really the whole question is sorta ill-posed, because you don’t know what other processes on the system are doing, and how many threads _they_ need. That’s a nice thing with GCD on macOS, is that you have shared global thread pools, but I digress…)

How about std:🧵:hardware\_concurrency ?

Sean

---

<div class="post-metadata">

### Author: ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)
#### Post date: [October 24, 2024, 1:34pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/4 "2024-10-24T13:34:32Z")

</div>

> [@seanm](#):
>
> How about std:🧵:hardware\_concurrency ?

This is currently used in some cases. Again it queries the hardware not what the OS has allocated to the processes.

> [@seanm](#):
>
> a nice thing with GCD on macOS, is that you have shared global thread pools,

I don’t think threads are shared between processes. The size of the thread pools in each process may be determined by the OS, and what other tasks it’s currently/dynamically doing.

> [@seanm](#):
>
> The `np` in `pthread_getaffinity_np` means ‘non portable’ and indeed this function does not seem to exist on the BSDs, including macOS.

Yes, the OS functions are not portable.

> [@dzenanz](#):
>
> A Windows equivalent might be [GetProcessAffinityMask()](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask). Also possibly relevant is [GetSystemInfo()](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo). [This discussion](https://stackoverflow.com/questions/76317127/windows-11-thread-affinities-spanning-multiple-processor-groups-explicitly) might be relevant too, if someone is looking into implementing it.

I would likely defer that to someone more invested or able to test in windows than my self.

---

<div class="post-metadata">

### Author: ![seanm](https://discourse.itk.org/letter_avatar_proxy/v4/letter/s/a88e4f/32.png) [@seanm](https://discourse.itk.org/u/seanm)
#### Post date: [October 24, 2024, 2:38pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/5 "2024-10-24T14:38:32Z")

</div>

Well, this is getting off-topic for ITK, but: GCD’s model is less about directly using threads and more about work pools. You put items in a work pool and the OS decides how/when to schedule them.

Trying to answer the question of ‘how many threads are available for ITK’ is still impossible and at best you can guess. The answer changes over time. CPU cores can be powered off/on, process come and go, and other processes may have lots or little work to do (that your process doesn’t know about), etc. Only the OS knows all these things.

---

<div class="post-metadata">

### Author: ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)
#### Post date: [October 24, 2024, 2:48pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/6 "2024-10-24T14:48:43Z")

</div>

> [@seanm](#):
>
> Only the OS knows all these things.

And one way some OS’s can communicate this to a process is via the processes affinity I have suggested to support.

P.S. I implemented a GCD thread for ITK… LOL, there are still some remnants: [WIP: GCD · blowekamp/ITK@32f4029 · GitHub](https://github.com/blowekamp/ITK/commit/32f402973a29ca7b424adc42449c3e3240e90520)

---

<div class="post-metadata">

### Author: ![seanm](https://discourse.itk.org/letter_avatar_proxy/v4/letter/s/a88e4f/32.png) [@seanm](https://discourse.itk.org/u/seanm)
#### Post date: [October 24, 2024, 5:30pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/7 "2024-10-24T17:30:44Z")

</div>

But does it? My understanding of those affinity API is that they are more about getting two threads running on the same CPU, so that if they are doing something like working on the same data they can share L1 cache and the like.

They don’t seem related to answering “how many threads can I use?”.

---

<div class="post-metadata">

### Author: ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)
#### Post date: [October 24, 2024, 7:24pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/8 "2024-10-24T19:24:23Z")

</div>

> [@seanm](#):
>
> They don’t seem related to answering “how many threads can I use?”.

I can get the following on a cluster job or something similar in a docker container:

```auto
taskset -p -c $$
pid 3137605's current affinity list: 50,52,54,56

```

That is my process ( and sub processes ) only have access to 4 cpus/cores of the 64+ cores on the system. ITK it defaulting to spinning up 64 threads.

---

<div class="post-metadata">

### Author: ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)
#### Post date: [May 12, 2025, 12:33pm UTC](https://discourse.itk.org/t/should-we-be-using-scheduler-affinity-for-default-number-of-threads/7278/9 "2025-05-12T12:33:14Z")

</div>

This was implemented in ITK with the following PR: [ENH: Use get\_schedaffin to determine number of threads by blowekamp · Pull Request #4927 · InsightSoftwareConsortium/ITK · GitHub](https://github.com/InsightSoftwareConsortium/ITK/pull/4927)
