# Parallelization on Windows

**URL:** <https://fortran-lang.discourse.group/t/parallelization-on-windows/9905>\
**Category:** Uncategorized\
**Created:** [July 4, 2025, 11:01am UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905 "2025-07-04T11:01:26Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![cwetaski](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@cwetaski](https://fortran-lang.discourse.group/u/cwetaski)\
**Post date:** [July 4, 2025, 11:01am UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/1 "2025-07-04T11:01:26Z")

</div>

Hi all,

I have quite a specific problem which I’m not super equipped to debug myself, and was wondering if someone had some insight.

I’m running my fortran program (gfortran 14.2.0 with openMP) on Windows 10, and my workstation has an intel xeon w9-3475x processor (36-core, 72-threads). As I understand it, Windows automatically groups threads into NUMA nodes with a maximum of 64 threads. This leads to an asymmetric grouping on my machine where I have 1 group with 64 threads (Node 0) and another with just 8 (Node 1). When I run my program, there seems to be a 50/50 chance which NUMA node it will run on, and it only uses the resources from the NUMA node it runs on. That means if it runs on Node 1, I get 64 threads and can happily parallelize with openMP. If it runs on Node 1, I only get 8 threads and the result is my code runs ~8-fold slower.

I’ve tried setting environment variables like  
OMP\_NUM\_THREADS = 72  
OMP\_PROC\_BIND = spread  
OMP\_PLACES = cores

But this hasn’t had any effect. Therefore, as I see it, my options are:

1. Force my application to always run on Node 0 so that I get 64 threads every time.

2. Disable hyperthreading, so that I have only 1 thread for each core and get a single group of 36 threads.

3. If I want to use all 72 threads with gfortran, I have to switch to a Linux environment (WSL) so that I can have a single group of 72 threads.

4. If I want to use all 72 threads with windows, I can switch to the intel compiler and configure it to use both processor groups.

Am I understanding this correctly? I think option 3 makes the most sense because since if I’m doing HPC I should really just stop avoiding linux.

Thanks,  
Charles

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 4, 2025, 11:32am UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/2 "2025-07-04T11:32:52Z")

</div>

> [@cwetaski](#):
>
> Disable hyperthreading, so that I have only 1 thread for each core and get a single group of 36 threads.

I don’t know anything about your code, but hyperthreading is most of time useless, and sometimes harmful, for most HPC codes.

---

<div class="post-metadata">

**Author:** ![jorgeg](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jorgeg/32/6835_2.png) [@jorgeg](https://fortran-lang.discourse.group/u/jorgeg)\
**Post date:** [July 4, 2025, 12:28pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/3 "2025-07-04T12:28:13Z")

</div>

> [@cwetaski](#):
>
> I think option 3 makes the most sense because since if I’m doing HPC I should really just stop avoiding linux.

Yeah…this is mostly it.

---

<div class="post-metadata">

**Author:** ![Jweber](https://avatars.discourse-cdn.com/v4/letter/j/e95f7d/32.png) [@Jweber](https://fortran-lang.discourse.group/u/Jweber)\
**Post date:** [July 5, 2025, 12:02pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/4 "2025-07-05T12:02:58Z")

</div>

However, if you run Linux within Windows I am not sure whether this removes the limitations of the underlying Windows systems (I, did however, no research concerning this specific problem).

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [July 5, 2025, 12:08pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/5 "2025-07-05T12:08:42Z")

</div>

> [@cwetaski](#):
>
> - Force my application to always run on Node 0 so that I get 64 threads every time.

Have you tried [`start`](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/start)?

```auto
$ start /node <0|1> prog.exe
```

---

<div class="post-metadata">

**Author:** ![cwetaski](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@cwetaski](https://fortran-lang.discourse.group/u/cwetaski)\
**Post date:** [July 5, 2025, 12:35pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/6 "2025-07-05T12:35:46Z")

</div>

Yes this works. It took me awhile to figure out though, since I normally use a powershell terminal and I wasn’t able to do figure out how to do the same in powershell. However if I’m running my program with fpm (i.e., `start /NODE 0 fpm run`) it doesn’t work since the child application launched by fpm isn’t bound to node 0. I could still write a script which builds and runs my programs using `start /NODE 0`.

Regardless, I think the WSL solution is what I’m going to go with.

---

<div class="post-metadata">

**Author:** ![cwetaski](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@cwetaski](https://fortran-lang.discourse.group/u/cwetaski)\
**Post date:** [July 5, 2025, 12:39pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/7 "2025-07-05T12:39:15Z")

</div>

Interesting point. I will try the WSL solution and find out, I guess!

---

<div class="post-metadata">

**Author:** ![cwetaski](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@cwetaski](https://fortran-lang.discourse.group/u/cwetaski)\
**Post date:** [July 5, 2025, 12:43pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/8 "2025-07-05T12:43:06Z")

</div>

Unfortunately I did some testing and in my case hyperthreading helps quite a lot: 64 threads performs about 30% faster than 36 nodes without hyperthreading.

---

<div class="post-metadata">

**Author:** ![Jweber](https://avatars.discourse-cdn.com/v4/letter/j/e95f7d/32.png) [@Jweber](https://fortran-lang.discourse.group/u/Jweber)\
**Post date:** [July 5, 2025, 5:08pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/9 "2025-07-05T17:08:41Z")

</div>

There seems to be a limit of 64 CPUs that can “trivially” utilized by a single process in Windows 10. This limitation seems to have been lifted in Windows 11.

You may search for "Windows’ and “Processor Group”. Again, I have no personal experience.

---

<div class="post-metadata">

**Author:** ![Jweber](https://avatars.discourse-cdn.com/v4/letter/j/e95f7d/32.png) [@Jweber](https://fortran-lang.discourse.group/u/Jweber)\
**Post date:** [July 5, 2025, 8:19pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/10 "2025-07-05T20:19:28Z")

</div>

This page might be helpful:

> **[Processor Groups - Win32 apps](https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups)**
>
> The 64-bit versions of Windows 7 and Windows Server 2008 R2 and later versions of Windows support more than 64 logical processors on a single computer. This functionality is not available on 32-bit versions of Windows.

---

<div class="post-metadata">

**Author:** ![Knarfnarf](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Knarfnarf](https://fortran-lang.discourse.group/u/Knarfnarf)\
**Post date:** [July 7, 2025, 1:47am UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/11 "2025-07-07T01:47:45Z")

</div>

I found that trying to double use (–oversubscribe) the physical cores on my computer just doubles the amount of time a thread takes. Hyperthreading is a marketing way of saying that another thread is ready to start executing when the first thread commits a cache miss ie: branch prediction loaded the wrong memory and must wait for L2/L3/system RAM to continue. If thread 0 of core 0 never fails to read a branch in time, thread 1 of core 0 will never get task time. That doesn’t help get an answer any faster!

I usually program in Open Co-Arrays on Linux for Windows because it’s nice and easy!

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 7, 2025, 6:31am UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/12 "2025-07-07T06:31:36Z")

</div>

@Knarfnarf It’s a little bit more complicated, and no, it is not just marketing. Hyperthreading (actually Simutaneous Multithreading = SMT) is primarily a hardware capability to really execute simultaneously some instructions from 2 different threads in the same core. For instance an integer addition for the thread 0 and a foating point multiplication for the thread 1, as these 2 operations do not use the same physical circuits.

Very roughtly speaking, SMT can help in the case where the two threads execute very different codes, as it increases the chances they don’t need the same resources at the very same time. In contrast, the parallelization of simple loops is generally not more efficient with SMT, as all the threads do the same kind of operations at the very same time.

---

<div class="post-metadata">

**Author:** ![cwetaski](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@cwetaski](https://fortran-lang.discourse.group/u/cwetaski)\
**Post date:** [July 7, 2025, 3:32pm UTC](https://fortran-lang.discourse.group/t/parallelization-on-windows/9905/13 "2025-07-07T15:32:42Z")

</div>

I went with WSL and it fixed my issues. Some notes for anyone who is curious.

Right away, there was no issue with NUMA nodes—querying `numactl --hardware` showed 72 cpus on a single node. However, when running my program, task manager still showed that it was only using up to 64 threads (this was still an improvement, because it was _always_ able to use 64 threads, rather than half the time getting 8).

To get 72 threads, I had to run (from a windows command prompt instance, not the linux environment)  
`bcdedit /set hypervisorschedulertype Core`

And now I can use up to 72 threads within WSL (running on windows is, however, still limited to 64 threads on node 0).
