High and variable launch + synchronize latency for small kernels (~56 µs, often 2x)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 43/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 技术栈
- julia
- 领域
- backend, performance
调研方向
Start with the two Julia reproducers in the issue and confirm the launch and synchronization latency distributions on the stated Arc A770 setup. Then trace the oneAPI.jl launch and synchronize paths to locate where the variable delay occurs. The issue is resolved when the source of the slow samples is identified and launch plus synchronize latency is reduced or made consistent.
由索引模型根据 Issue 内容生成。
描述
Launching a trivial kernel and synchronizing takes about 56 µs on an Arc A770. A noticeable share of calls take twice that or more:
- the launch itself costs about 18 µs of host time, and still 15 µs per launch when 1000 launches are queued back to back with a single synchronize at the end;
synchronizethen takes a median of 39 µs, with a p90 of 110 µs;- back to back, about 10% of launch+sync calls take 125–155 µs instead of 56 µs. After the host has been idle for 1 ms, the median is 97–117 µs.
synchronize(blocking=true)behaves the same.
For small problems this dominates. We ran into it in JuliaGPU/AcceleratedKernels.jl#194, where medians of back-to-back calls on 10^4 elements flipped by ±30% between runs, depending on the share of slow samples. Earlier, with heavier kernels and some background CPU load, back-to-back calls were bimodal at about 60 µs and 125–155 µs, with each process tending to stay in one mode. I haven't found out whether the cost is in oneAPI.jl's launch path, Level Zero, or the GPU's power management.
launch: p10 17.0 p50 17.9 p90 18.6 µs
sync: p10 37.7 p50 39.0 p90 109.7 µs
1000 back-to-back launches + 1 sync: 15.1 µs per launch
blocking=false gap 0 µs: p10 55.8 p50 56.7 p90 127.8 µs
blocking=false gap 10 µs: p10 56.4 p50 58.4 p90 59.8 µs
blocking=false gap 50 µs: p10 56.6 p50 57.1 p90 59.3 µs
blocking=false gap 1000 µs: p10 69.5 p50 96.9 p90 149.4 µs
blocking=true gap 0 µs: p10 55.6 p50 56.4 p90 126.9 µs
blocking=true gap 1000 µs: p10 70.5 p50 117.2 p90 148.7 µs
Environment: oneAPI.jl 2.10.0, NEO 26.35.39758, libigc 2.41.5, Level Zero API 1.17, Julia 1.13.2, Arc A770, Linux 7.2.11 (Arch), otherwise idle machine.
Reproducers
# Split launch + sync of a trivial kernel: host time of the launch, of the synchronize, and the device time
using oneAPI, Statistics, Printf
z = oneArray(zeros(Float32, 1))
k(a) = (@inbounds a[1] = 1f0; nothing)
for _ in 1:100; @oneapi k(z); oneAPI.synchronize(); end
tl = Float64[]; ts = Float64[]
for _ in 1:1000
t0 = time_ns(); @oneapi k(z); t1 = time_ns(); oneAPI.synchronize(); t2 = time_ns()
push!(tl, (t1 - t0) / 1e3); push!(ts, (t2 - t1) / 1e3)
end
@printf("launch: p10 %5.1f p50 %5.1f p90 %5.1f µs\n", quantile(tl, [0.1, 0.5, 0.9])...)
@printf("sync: p10 %5.1f p50 %5.1f p90 %5.1f µs\n", quantile(ts, [0.1, 0.5, 0.9])...)
# launch-only throughput: 1000 launches, one sync
t = @elapsed (for _ in 1:1000; @oneapi k(z); end; oneAPI.synchronize())
@printf("1000 back-to-back launches + 1 sync: %.1f µs per launch\n", 1e6 * t / 1000)
# Wall time of launching a trivial kernel and synchronizing, after the host idles for `gap` µs
using oneAPI, Statistics, Printf
z = oneArray(zeros(Float32, 1))
k(a) = (@inbounds a[1] = 1f0; nothing)
function spin(us)
t = time_ns() + round(UInt64, us * 1000)
while time_ns() < t; end
end
for blocking in (false, true)
for _ in 1:100; @oneapi k(z); oneAPI.synchronize(; blocking); end
for gap in (0, 10, 25, 50, 100, 1000)
ts = Float64[]
for _ in 1:500
spin(gap)
push!(ts, 1e6 * @elapsed (@oneapi k(z); oneAPI.synchronize(; blocking)))
end
q = quantile(ts, [0.1, 0.5, 0.9])
@printf("blocking=%-5s gap %4d µs: p10 %6.1f p50 %6.1f p90 %6.1f µs\n", blocking, gap, q...)
end
end
- 主要语言
- Julia
- 星标
- 218
- 派生
- 36
- 平均合并
- 1 天 6 小时
- 30 天内合并 PR
- 65
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
JuliaGPU/oneAPI.jl 的其他 Issue
-
难度 4/5 1-2 天 新手友好度 55/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 48/100
JuliaGPU/oneAPI.jl#750 · 1 条评论 ·
维护者通常 1 天内回复
-
performance
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 1 天内回复
-
libraries upstream
难度 4/5 1-2 天 新手友好度 22/100
JuliaGPU/oneAPI.jl#703 · 2 条评论 ·
维护者通常 1 天内回复
-
ci
难度 5/5 一周以上 新手友好度 35/100
JuliaGPU/oneAPI.jl#663 · 1 个 reaction ·
维护者通常 1 天内回复
查看 JuliaGPU/oneAPI.jl 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 72/100
-
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
documentation invalid
难度 1/5 1-3 小时 新手友好度 88/100
JuliaPhysics/BeamletOptics.jl#190 ·
维护者通常 2 天内回复
-
mul! with a Symmetric or Hermitian factor throws for a matrix view whose columns are not contiguous可能已有人在做 @dkarrasch 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
JuliaLang/LinearAlgebra.jl#1829 ·
维护者通常 1 天内回复
-
`EnsembleSummary` `ci_type = :SEM` ribbon is `sqrt(N)` too wide for scalar states可能已有人在做 @isaacsas 于 1 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 88/100
SciML/SciMLBase.jl#1654 ·
维护者通常 3 天内回复