Kernel launches are compiled for Vararg{Any} and dispatched at run time
维护者通常 1 天内回复
已经有一个关联 PR 被合并了。
- #687 来自 @maleadt —— 已合并
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 30/100
- Issue 类型
- 重构
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 领域
- compilers, performance
调研方向
Start with code_typed on a kernel call to confirm the Vararg{Any} specialization in src/oneAPIKernels.jl (around line 119) and src/compiler/execution.jl (around line 403). Then look at zefunction (lines 287-323), device() in src/context.jl, and setindex! in lib/level-zero/module.jl. Done means the changes infer fully and precompile timing drops for a new signature, which needs an Intel GPU to verify launches.
由索引模型根据 Issue 内容生成。
描述
JuliaGPU/Metal.jl#1014 cut the host-side compilation needed to launch a kernel with a new argument signature by 4-10x on Metal. I checked which of the causes found there also apply to oneAPI.jl; several do, and here they also make every launch go through dynamic dispatch.
I don't have an Intel GPU, so this is based on code_typed and on timing precompile of a function launching a new kernel signature, with the changes below prototyped by redefining the functions.
(obj::KA.Kernel{oneAPIBackend})(args...; ndrange, workgroupsize)(src/oneAPIKernels.jl:119) and(kernel::HostKernel)(args...; kwargs...)(src/compiler/execution.jl:403) are compiled forVararg{Any}, e.g.(..., ::oneArray{Float32,...}, ::Vararg{Any}), even when called from concretely typed code: Julia doesn't specialize a method on varargs it only passes on. That includes the@oneapimacro expansion. Everything after that point is dispatched at run time (map(kernel_convert, ...),zefunction,call,launch_configuration), so each new signature gets compiled piecemeal during its first launch, and every launch pays for the dispatches. Metal.jl fixed this withargs::Vararg{Any,N} ... where N.zefunction(src/compiler/execution.jl:287-323) compiles its whole body for every kernel.device()(src/context.jl:74-78) infers asAny, which makescompiler_config, the comparisons,hashand the conversion dynamic. Theget!(_kernel_instances, h) do HostKernel{F,tt}(f, fun) endclosure has a new type for every kernel, soget!is compiled per kernel as well, even though aHostKernelis only(f, fun)and needs no cache. Splitting it likecufunctionandcufunction_linkin CUDA.jl, withdevice()::ZeDevice, leaves no dynamic calls on the@oneapipath.setindex!(::ZeKernelArgumentList, value, i)(lib/level-zero/module.jl:208-211) is compiled per argument type with the@checked zeKernelSetArgumentValuewrapper inlined. Computing the size and address per type and calling an unspecialized@noinlinesetter saves ~13 ms per new signature.launch_configuration(src/compiler/execution.jl:246) returnsUnion{Missing,Int}, because checkingkernel_props.maxGroupSize !== missingdoesn't narrow a later field access. As a resultthreads_to_workgroupsizereturnsTuple{Any}, and the finalkernel(ctx, args...; items, groups)in the KernelAbstractions launch is a dynamic call. Binding the field to a local first fixes that.
With the first three changes the whole path is inferred, and precompile puts a new signature at ~50 ms (Julia 1.12) / ~44 ms (1.13) for @oneapi and ~31 ms through KernelAbstractions. I can't give a meaningful number for the current code without a GPU, because most of its launch path is only compiled during the launch itself.
- 主要语言
- Julia
- 星标
- 218
- 派生
- 36
- 平均合并
- 1 天 14 小时
- 30 天内合并 PR
- 59
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
JuliaGPU/oneAPI.jl 的其他 Issue
-
ci kernels upstream
难度 5/5 一周以上 新手友好度 35/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 43/100
维护者通常 1 天内回复
-
难度 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 天内回复
查看 JuliaGPU/oneAPI.jl 的全部 Issue
相似的 Issue
-
lux
难度 2/5 1-3 小时 新手友好度 76/100
JuliaGraphs/GraphNeuralNetworks.jl#732 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
erfinv(::Float16) and erfcinv(::Float16) are wrong for abs(x) <= 0.75 (erfinv(Float16(0)) == 0.2201)未关闭
难度 2/5 1-3 小时 新手友好度 82/100
JuliaMath/SpecialFunctions.jl#571 ·
-
难度 2/5 1-3 小时 新手友好度 74/100
-
难度 2/5 1-3 小时 新手友好度 67/100