How can I measure total CPU time?
Standard tool to measure total cpu time is getrusage(2). We can do this in Julia as follows:
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> 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.
How can I measure false sharing?
Standard tool is perf-c2c(1). 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