# Benchmarking and threads

**URL:** <https://discourse.julialang.org/t/benchmarking-and-threads/138593>\
**Category:** Performance\
**Tags:** multithreading, benchmark, benchmarktools\
**Created:** [August 5, 2026, 5:45am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593 "2026-08-05T05:45:58Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [August 5, 2026, 5:45am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/1 "2026-08-05T05:45:58Z")

</div>

> **[GitHub - phma/Kaftor.jl: Keyed affine transform](https://github.com/phma/Kaftor.jl)**
>
> Keyed affine transform

In the `bench` workspace, I have this function:

```julia-auto
function kaftorTime(textLen::Integer,keyLen::Integer) # in nanoseconds
  text=fill(0x69,textLen)
  key=fill(0x96,keyLen)
  trial=@benchmark kaftorEncrypt!($text,$key)
  median(trial).time
end

```

I have two Julias running, one `julia --project -t auto` (which is 12) and one `julia --project -t 1`. (This is on my old tower; my new laptop has 32 threads and is significantly faster.) With 12 threads:

```julia-auto
julia> kaftorTime(59049,32)/59049
637.9849531744823

```

With 1 thread:

```julia-auto
julia> kaftorTime(59049,32)/59049
337.4873240867754

```

I don’t see how that can happen unless `@bench` is measuring total CPU time on all cores.

I’d like to tune the parallelized parts of the algorithm, with the number of threads depending on the message size, to minimize the elapsed time without greatly increasing the task switching overhead. Can I measure both elapsed time and total time of all threads? Also, is there a way to specify the number of threads that `@threads` uses?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [August 5, 2026, 7:51am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/2 "2026-08-05T07:51:56Z")

</div>

Did you try with 2, 3, 4 … threads?

Most CPUs now have fast and slow cores. Using the slow cores is often useless and can slow things down, depending on your algorithm.

Threads can slow things down by:

- causing more GC pressure
- causing communication/ coordination overhead

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [August 5, 2026, 8:10am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/3 "2026-08-05T08:10:31Z")

</div>

The tower has only one kind of core. The laptop has two.

The algorithm does three things per round: `jumble!`, `shufflePairs!`, and `mix3PartsSeq!`; all of which operate on a vector in place, so there shouldn’t be any garbage collection. `jumble!` is already parallelized, with a worker function, so I can easily change the number of threads. `shufflePairs!` is parallelized with `@threads`; this produced a slight speedup. Replacing `mix3PartsSeq!` with `mix3PartsPar!` slowed it down.

Profiling it results in most of the time spent in `task_done_hook`, which doesn’t help me see what’s going on.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [August 5, 2026, 8:51am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/4 "2026-08-05T08:51:44Z")

</div>

There are a lot of ways this can happen.

If your program is abusing the Task system and spawns too many short-running tasks, then you will see this behavior: When single-threaded, the entire task-switching / scheduling apparatus is faster.

You can also see this if your parallelization sucks, i.e. if you have lots of contention, irregardless of whether false sharing (different cores access different parts of the same cache-line) or true sharing (e.g. locks / contested atomics or data races). In such cases single-threaded is much faster.

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [August 6, 2026, 4:59am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/5 "2026-08-06T04:59:11Z")

</div>

It appears, from looking at the source, that `@bench` is measuring elapsed time. How can I measure total CPU time?

Is there a way to specify the number of threads that `@threads` uses? Or do I have to create a worker function?

How can I measure false sharing? There is no true sharing in this program; each iteration of a loop operates on a different pair or triple of bytes.

---

<div class="post-metadata">

**Author:** ![BjarkeHautop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarkehautop/32/219291_2.png) [@BjarkeHautop](https://discourse.julialang.org/u/BjarkeHautop)\
**Post date:** [August 8, 2026, 9:33am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/6 "2026-08-08T09:33:16Z")

</div>

> How can I measure total CPU time?

Standard tool to measure total cpu time is [`getrusage(2)`](https://man7.org/linux/man-pages/man2/getrusage.2.html). We can do this in Julia as follows:

```julia
function cputime()
    buf = zeros(Int64, 18) # struct rusage: 2 timevals + 14 longs = 144 bytes
    ccall(:getrusage, Cint, (Cint, Ptr{Cvoid}), 0, buf) # 0 = RUSAGE_SELF
    (buf[1] + buf[3]) + (buf[2] + buf[4]) / 1e6 # (utime.sec+stime.sec) + usec/1e6
end

function kaftorTimes(textLen::Integer, keyLen::Integer; samples=100)
    text0 = fill(0x69, textLen)
    key = fill(0x96, keyLen)
    kaftorEncrypt!(copy(text0), key) # warm up
    elapsed = Float64[]; cpu = Float64[]
    for _ in 1:samples
        text = copy(text0)
        t0 = time_ns(); c0 = cputime()
        kaftorEncrypt!(text, key)
        push!(elapsed, (time_ns() - t0) / 1e9)
        push!(cpu, cputime() - c0)
    end
    (median(elapsed), median(cpu))
end

```

Running this with `-t 12` gives for me:

```julia
julia> kaftorTimes(59049,32)
(0.030032722, 0.11667699999999925)

```

> Is there a way to specify the number of threads that `@threads` uses? Or do I have to create a worker function?

No there isn’t. You need a worker function, or use a package such as [OhMyThreads](https://github.com/JuliaFolds2/OhMyThreads.jl).

> How can I measure false sharing?

Standard tool is [`perf-c2c(1)`](https://man7.org/linux/man-pages/man1/perf-c2c.1.html). I ran it, and there isn’t any false sharing happening.

The slowdown you see is just the overhead of using multiple threads, confirmed by the hits found by `perf-c2c(1)`, that it’s Julia’s own task scheduler.

> The algorithm does three things per round: jumble!, shufflePairs!, and mix3PartsSeq!; all of which operate on a vector in place, so there shouldn’t be any garbage collection. jumble! is already parallelized, with a worker function, so I can easily change the number of threads. shufflePairs! is parallelized with @threads; this produced a slight speedup. Replacing mix3PartsSeq! with mix3PartsPar! slowed it down.

That tracks with what `perf c2c` showed: `mix3PartsPar!` spawns `nthreads()` tasks unconditionally, no size check like `jumble!` has.

I did the following changes:  
I gave it the same kind of gate `jumble!` uses. Additionally, I changed so if the task count was 1 to not do `@spawn`+`wait`, since it gives an overhead.

With both fixes in, swapping `mix3PartsSeq!` for `mix3PartsPar!` is a win. I now get roughly same timings on the 59KB case with 12 threads as with a single thread, and over 2 times faster on 4MB.

[PR](https://github.com/phma/Kaftor.jl/pull/1)

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [August 8, 2026, 4:57pm UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/7 "2026-08-08T16:57:10Z")

</div>

> [@phma](#):
>
> Is there a way to specify the number of threads that `@threads` uses? Or do I have to create a worker function?

You can launch Julia with the -t flag set to the number of threads you’d like. But once started that can’t be changed.  
If you want fine grained control you’ll have to start working with tasks, but those don’t map exactly to threads unless you pin them.

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [August 9, 2026, 7:51am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/8 "2026-08-09T07:51:43Z")

</div>

> [@BjarkeHautop](#):
>
> I gave it the same kind of gate `jumble!` uses. Additionally, I changed so if the task count was 1 to not do `@spawn`+`wait`, since it gives an overhead.

What do you mean by “gate”?

I put `perThread` in after starting this discussion. I’m planning to do the same for `mix3Parts!` and probably `shufflePairs!` (with a worker function) as well. I adjusted `perThread` by benchmarking it with message sizes up to 3^17, which is close to 2^27.

---

<div class="post-metadata">

**Author:** ![BjarkeHautop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarkehautop/32/219291_2.png) [@BjarkeHautop](https://discourse.julialang.org/u/BjarkeHautop)\
**Post date:** [August 9, 2026, 9:05am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/9 "2026-08-09T09:05:32Z")

</div>

> [@phma](#):
>
> What do you mean by “gate”?

Did you see the PR I made? But just like in your `jumple!` function I added

```julia
aInc=max(1,min(len÷mix3PerThread,nthreads()))

```

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [August 9, 2026, 9:14am UTC](https://discourse.julialang.org/t/benchmarking-and-threads/138593/10 "2026-08-09T09:14:02Z")

</div>

I have not looked at the repo yet, nor worked on the program. You posted when it was Sabbath here. I normally sleep after lunch on Saturdays, but there was a capacitation at church, so I went back to church in the afternoon and got home tired. Also I’ve been working on another project called Propolis, which is in C++.
