# \[ANN\] Announcing ThreadPinning.jl

**URL:** <https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230>\
**Category:** Package Announcements\
**Tags:** multithreading\
**Created:** [December 28, 2022, 1:41pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230 "2022-12-28T13:41:24Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [December 28, 2022, 1:41pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/1 "2022-12-28T13:41:24Z")

</div>

Hi all,

It’s already been out there for a while but I nonetheless wanted to properly announce [ThreadPinning.jl](https://github.com/carstenbauer/ThreadPinning.jl/) here. 🙂

### What is ThreadPinning.jl about?

In short, it’s about pinning Julia threads to specific CPU-cores. To that end, it provides

1. a convenient visualisation of the system topology and the current thread-core mapping, and
2. tools to fully control and specify the latter.

### First impression / demonstration

Dual-socket system where each CPU has 40 hardware threads (20 CPU-cores with 2-way [SMT](https://en.wikipedia.org/wiki/Simultaneous_multithreading)).

 ![image](https://global.discourse-cdn.com/julialang/original/3X/2/c/2cdcde7174511afb8285ff5ad96f6922b9b75bb5.png)

Besides using the `pinthreads` function directly, which is the most powerful interface, you can also specify the thread-core mapping via environment variables or Julia preferences. See [this section of the docs](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_pinning_julia_threads/) for more information.

### Why care about thread pinning?

#### 1) Performance

When you run a multithreaded Julia computation, by default, you’re leaving it to the operating system to distribute your Julia threads among the cores of your CPU(s). While the OS tries to smartly position your threads on the system, it might, for various reasons, make suboptimal choices. For example, it might place multiple Julia threads on the same core or move Julia threads around during the computation. This can dramatically reduce the performance of your computation, especially on more complicated systems such as HPC cluster nodes with multiple CPUs (typically two) and multiple memory domains (NUMA) per CPU.

(Even if you pin your threads, there are, of course, many different thread-core mappings that one can imagine, each of which can lead to very different performance (see [here](https://github.com/JuliaPerf/BandwidthBenchmark.jl#flopsscaling) for a simple example).)

#### 2) Hardware performance monitoring

A number of low-level tools operate on a CPU-core level and, to use them, you need to know or need to specify on which CPU-core your Julia thread is running. One example is [LIKWID.jl](https://github.com/JuliaPerf/LIKWID.jl) which allows you to measure the performance of Julia code on a hardware level by monitoring hardware counters inside of CPU-cores (see [my JuliaCon 2022 talk](https://www.youtube.com/watch?v=l2fTNfEDPC0) about this). In fact, LIKWID.jl’s `@perform` macro uses ThreadPinning.jl under the hood to make sure that the Julia thread actually runs on the monitored CPU-core (and also stays there).

#### 3) Reducing fluctuations in benchmarks

By implementing a particular Julia thread-core mapping, you reduce fluctuations in performance benchmarks which would otherwise originate from the OS deciding to place Julia threads on different cores between benchmark runs.

#### (Extra: System analysis: Core-to-core latency measurements)

> **[Core-to-Core Latency · ThreadPinning.jl](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_core2core_latency/)**
>
> Documentation for ThreadPinning.jl.

### Limitation: Currently Only Linux

ThreadPinning.jl currently only supports Linux. See [here](https://carstenbauer.github.io/ThreadPinning.jl/stable/explanations/linux/) for why this is and how you can help to add Windows support.

Hope you find the package useful. Looking forward to questions, issues, and/or PRs 🙂

All the best,  
Carsten

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [December 28, 2022, 1:56pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/2 "2022-12-28T13:56:35Z")

</div>

Would this work for me if I run it through WSL?

Just so I can get that kind of overview.

Kind regards

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [December 28, 2022, 2:08pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/3 "2022-12-28T14:08:48Z")

</div>

Good question. I never explicitly considered WSL and I would be surprised if it worked out of the box. OTOH, for `threadinfo` to work, essentially only lscpu is required (and `Sys.islinux() == true` since I currently explicitly throw an error for others OSs). Maybe just try it? If it doesn’t work, it would be interesting to see what’s missing, so please file an issue.

---

<div class="post-metadata">

**Author:** ![AMJ](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amj/32/214096_2.png) [@AMJ](https://discourse.julialang.org/u/AMJ)\
**Post date:** [December 28, 2022, 2:47pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/4 "2022-12-28T14:47:24Z")

</div>

Great work.

Is something similar being introduced in Julia1.9 ?

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [December 28, 2022, 3:36pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/5 "2022-12-28T15:36:31Z")

</div>

> [@AMJ](#):
>
> Great work.

Thanks.

> [@AMJ](#):
>
> Is something similar being introduced in Julia1.9 ?

Not sure what you mean, but no. This is fine in a package (which can evolve much faster).

---

<div class="post-metadata">

**Author:** ![AMJ](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amj/32/214096_2.png) [@AMJ](https://discourse.julialang.org/u/AMJ)\
**Post date:** [December 29, 2022, 7:17am UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/6 "2022-12-29T07:17:56Z")

</div>

I was mistaken, talking about [this](https://www.youtube.com/watch?v=N4h46_TCmGc&t=1019s) presentation that Jeff did about interactive thread pools at 18:13.

---

<div class="post-metadata">

**Author:** ![spcogg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/spcogg/32/16943_2.png) [@spcogg](https://discourse.julialang.org/u/spcogg)\
**Post date:** [December 30, 2022, 6:14am UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/7 "2022-12-30T06:14:56Z")

</div>

Just chiming in to say another big use case is for high-availability requests in production workloads! We currently have a Julia backend microservices stack which requires a monitoring heartbeat to keep the service alive every x seconds.

Before threadpinning, when a service was cpu bound, it couldn’t reply to the cluster keep-alive heartbeat, resulting in the service being killed when it was legitimately busy, and not actually dead. So now we keep at least 1 CPU free to reply to the heartbeats / supply the monitoring metrics etc.

Big props for this package!

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [December 30, 2022, 8:55am UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/8 "2022-12-30T08:55:45Z")

</div>

What I forgot to mention in the OP: ThreadPinning.jl also has beta-level support for pinning **OpenBLAS threads**.

 ![Screenshot 2022-12-30 at 09.48.57](https://global.discourse-cdn.com/julialang/original/3X/0/0/002fca5669e30a5b03b99d1e52d34c30250b1702.png)

See [BLAS/LAPACK · ThreadPinning.jl](https://carstenbauer.github.io/ThreadPinning.jl/stable/refs/blaslapack/) for the function references.

Note, though, that querying the affinity of OpenBLAS threads (i.e. `openblas_getcpuids` and `openblas_print_affinity_masks` in the example above) requires Julia \>= 1.9 because the underlying API on the OpenBLAS side has only [been added](https://github.com/xianyi/OpenBLAS/pull/3702) in OpenBLAS v0.3.21. Pinning the threads “blindly” should also work on Julia \>= 1.6.

---

<div class="post-metadata">

**Author:** ![roh\_codeur](https://avatars.discourse-cdn.com/v4/letter/r/ce73a5/32.png) [@roh\_codeur](https://discourse.julialang.org/u/roh_codeur)\
**Post date:** [September 17, 2023, 2:32pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/9 "2023-09-17T14:32:23Z")

</div>

hi, thanks for your work on this, sounds awesome.

say, I have Linux running on Docker on a Mac. do you think this package will have the same impact as running on a native Linux distribution?

thanks

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [September 17, 2023, 10:00pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/10 "2023-09-17T22:00:45Z")

</div>

> [@roh\_codeur](#):
>
> say, I have Linux running on Docker on a Mac. do you think this package will have the same impact as running on a native Linux distribution?

No, unlikely.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [September 17, 2023, 10:01pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/11 "2023-09-17T22:01:44Z")

</div>

For those who are interested, here is my JuliaCon 2023 talk about ThreadPinning.jl:

[![](https://global.discourse-cdn.com/julialang/original/3X/e/2/e25c844f4062abbb55f927844061216e4e468da1.jpeg "Pinning Julia Threads to CPU-Cores with ThreadPinning.jl | Carsten Bauer | JuliaCon 2023") ](https://www.youtube.com/watch?v=6Whc9XtlCC0)

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 13, 2023, 5:49pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/12 "2023-11-13T17:49:46Z")

</div>

Since the docs mention that they help to make benchmarking more consistent, could you say a few words how can that be compared/combined to `cpuset` proposed in [Linux-based environments · BenchmarkTools.jl](https://juliaci.github.io/BenchmarkTools.jl/stable/linuxtips/#Processor-shielding-and-process-affinity)

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [November 13, 2023, 6:19pm UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/13 "2023-11-13T18:19:08Z")

</div>

ThreadPinning.jl doesn’t protect the CPU-threads from the scheduler (i.e. other processes). It only ensures that the Julia threads run where you want them run and don’t migrate away. I would therefore say that the cset shield is complementary.

I personally don’t need a shield because I’m working on HPC compute nodes which are essentially empty (i.e. there are only few other system processes).

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [August 8, 2024, 8:50am UTC](https://discourse.julialang.org/t/ann-announcing-threadpinning-jl/92230/14 "2024-08-08T08:50:37Z")

</div>

# Release of ThreadPinning.jl 1.0

Hey everyone,

I’ve released 1.0 yesterday 🎉 .

## What’s new?

- [Pinning and visualizing OpenBLAS threads](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_blas/) (has been very muched improved and is part of the official API now)
- [Pinning (Julia threads) of MPI ranks](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_mpi/)
- [Pinning (Julia threads) of Julia workers (Distributed.jl)](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_distributed/)
- [Pinning according to an external affinity mask](https://carstenbauer.github.io/ThreadPinning.jl/stable/examples/ex_affinity/)
- Experimental support for pinning GC threads (Julia \>= 1.11)
- `threadinfo()` now works on Windows and macOS (but most other things still won’t work)
- and much more…

Behind the scenes, there are two new backends: [SysInfo.jl](https://github.com/carstenbauer/SysInfo.jl) (based on Hwloc.jl and `lscpu`) and [ThreadPinningCore.jl](https://github.com/carstenbauer/ThreadPinningCore.jl). The requirement of `lscpu` being available has been dropped.

For more information, check out the [improved documentation](https://carstenbauer.github.io/ThreadPinning.jl/stable/).

## Want to transition from pre 1.0?

There are some minor API changes and some (unpopular) features have been dropped. Please consult the [API documentation](https://carstenbauer.github.io/ThreadPinning.jl/stable/refs/api_pinning/) and → check out the [CHANGELOG.md](https://github.com/carstenbauer/ThreadPinning.jl/blob/main/CHANGELOG.md).

## Want to help improve the stability of the package? (\< 5 min)

If you have a system (e.g. HPC compute node) that has a particularly interesting/strange hardware topology, please consider adding the system as a “fake testsystem” to SysInfo.jl by following the [(very short!) instructions](https://github.com/carstenbauer/SysInfo.jl#adding-your-system-as-a-test-system) here.

## Impressions

 ![image](https://global.discourse-cdn.com/julialang/original/3X/f/5/f5f370515bbc5b4c774a48c8f6a0430ab53b8a2a.jpeg)

 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/b/7b791055a00cf4b55bbcf9b67e98924eb6a782ae.jpeg)
