Comments (6)
- something about libcmt calling a method on disposed MTLCmdBuffer
It's very well possible there's some bugs in (the code I added to) cmt, as I wasn't familiar with CoreFoundation and its memory management semantics. It's also possible we're doing something wrong on the Julia side, calling mtRelease
early or so. Keep up posted about anything you find!
from metal.jl.
NOTE: Can maybe be ignored
I'm not making much progress with this. I modified MTL to try to debug calls to unsafe_destroy!:
function debug_finalizer(obj)
st = stacktrace()
t = time_ns()
x -> begin
Core.write(Core.stdout, "**********************\n")
Core.write(Core.stdout, "Finalizer called on $(obj), allocated at $(Int(t))\n")
Core.write(Core.stdout, "Allocation stack trace:\n")
for f=st
Core.write(Core.stdout, "\t$f\n")
end
Core.write(Core.stdout, "**********************\n\n")
unsafe_destroy!(obj)
end
end
and then modified all calls to finalizer
in MTL to look like:
finalizer(debug_finalizer(obj), obj)
From that output it does not look like Metal.jl is not doing anything wrong.
It is possible that the gtk main loop and metal compute and libuv are interacting in some bad way, but that is very vague and not actionable. Anyway, that's the update.
from metal.jl.
NOTE: Can maybe be ignored
Output looks like:
❯ julia --project -t 1 mtl.jl
97842
init
**********************
Finalizer called on MtlComputeCommandEncoder(Ptr{Metal.cmt.MtComputeCommandEncoder} @0x0000600003d6e400, MtlCommandBuffer(...)), allocated at 1802636834226708
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
#MtlComputeCommandEncoder#10 at compute.jl:21 [inlined]
MtlComputeCommandEncoder at compute.jl:14 [inlined]
MtlComputeCommandEncoder(f::Metal.var"#42#44"{MtSize, MtSize, Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}, Tuple{MtlMatrix{RGB{N0f8}}, Int64}, Vector{MtlBuffer}}, cmdbuf::MtlCommandBuffer; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) at compute.jl:50
MtlComputeCommandEncoder(f::Function, cmdbuf::MtlCommandBuffer) at compute.jl:49
(::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}})(::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}; grid::Tuple{Int64, Int64}, threads::Tuple{Int64, Int64}, queue::MtlCommandQueue) at execution.jl:207
(::Core.var"#Any##kw")(::NamedTuple{(:threads, :grid), Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}}}, ::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}, ::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}) at execution.jl:193
macro expansion at execution.jl:66 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
window
gtk4 main loop
for loop**********************
Finalizer called on MtlCommandBuffer(...), allocated at 1802636955672166
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlCommandBuffer at command_buf.jl:97 [inlined]
MtlCommandBuffer(queue::MtlCommandQueue) at command_buf.jl:95
synchronize at state.jl:51 [inlined]
synchronize() at state.jl:51
top-level scope at utilities.jl:11
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlCommandBufferDescriptor(...), allocated at 1802636954164125
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlCommandBufferDescriptor at command_buf.jl:19 [inlined]
MtlCommandBuffer(queue::MtlCommandQueue) at command_buf.jl:95
synchronize at state.jl:51 [inlined]
synchronize() at state.jl:51
top-level scope at utilities.jl:11
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlCommandBuffer(...), allocated at 1802636796669666
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlCommandBuffer at command_buf.jl:97 [inlined]
MtlCommandBuffer(queue::MtlCommandQueue) at command_buf.jl:95
(::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}})(::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}; grid::Tuple{Int64, Int64}, threads::Tuple{Int64, Int64}, queue::MtlCommandQueue) at execution.jl:204
(::Core.var"#Any##kw")(::NamedTuple{(:threads, :grid), Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}}}, ::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}, ::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}) at execution.jl:193
macro expansion at execution.jl:66 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlCommandBufferDescriptor(...), allocated at 1802636795101875
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlCommandBufferDescriptor at command_buf.jl:19 [inlined]
MtlCommandBuffer(queue::MtlCommandQueue) at command_buf.jl:95
(::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}})(::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}; grid::Tuple{Int64, Int64}, threads::Tuple{Int64, Int64}, queue::MtlCommandQueue) at execution.jl:204
(::Core.var"#Any##kw")(::NamedTuple{(:threads, :grid), Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}}}, ::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}, ::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}) at execution.jl:193
macro expansion at execution.jl:66 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
signal (11): Segmentation fault: 11
in expression starting at /Users/nehal/src/MetalGtk4Bug/mtl.jl:36
objc_release at /usr/lib/libobjc.A.dylib (unknown line)
Allocations: 34721736 (Pool: 34704344; Big: 17392); GC: 33
**********************
Finalizer called on MtlCommandQueue(Ptr{Metal.cmt.MtCommandQueue} @0x000000016e8f9000, MtlDevice(Apple M1 Max)), allocated at 1802636768444791
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlCommandQueue at command_queue.jl:29 [inlined]
(::Metal.var"#3#4"{MtlDevice})() at state.jl:33
get! at iddict.jl:178 [inlined]
global_queue(dev::MtlDevice) at state.jl:32
(::Core.var"#Any##kw")(::NamedTuple{(:threads, :grid), Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}}}, ::Metal.HostKernel{typeof(generate), Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}, ::MtlMatrix{RGB{N0f8}}, ::Vararg{Any}) at execution.jl:193
macro expansion at execution.jl:66 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlComputePipelineState(Ptr{Metal.cmt.MtComputePipelineState} @0x000000012295a890, MtlDevice(Apple M1 Max)), allocated at 1802636669502875
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlComputePipelineState(d::MtlDevice, f::MtlFunction) at compute_pipeline.jl:122
mtlfunction_link(job::GPUCompiler.CompilerJob, compiled::NamedTuple{(:image, :entry), Tuple{Vector{UInt8}, String}}) at execution.jl:177
cached_compilation(cache::Dict{UInt64, Any}, job::GPUCompiler.CompilerJob, compiler::typeof(Metal.mtlfunction_compile), linker::typeof(Metal.mtlfunction_link)) at cache.jl:95
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}; name::Nothing, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) at execution.jl:148
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}) at execution.jl:141
macro expansion at execution.jl:64 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlFunction(_Z19julia_generate_137014MtlDeviceArrayI3RGBI6NormedI5UInt8Li8EEELi2ELi1EE5Int64), allocated at 1802636666550291
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlFunction(lib::MtlLibrary, name::String) at function.jl:102
mtlfunction_link(job::GPUCompiler.CompilerJob, compiled::NamedTuple{(:image, :entry), Tuple{Vector{UInt8}, String}}) at execution.jl:175
cached_compilation(cache::Dict{UInt64, Any}, job::GPUCompiler.CompilerJob, compiler::typeof(Metal.mtlfunction_compile), linker::typeof(Metal.mtlfunction_link)) at cache.jl:95
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}; name::Nothing, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) at execution.jl:148
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}) at execution.jl:141
macro expansion at execution.jl:64 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
**********************
Finalizer called on MtlLibrary(MtlDevice(Apple M1 Max)), allocated at 1802636664893416
Allocation stack trace:
debug_finalizer at MTL.jl:29 [inlined]
MtlLibraryFromData(device::MtlDevice, data::Vector{UInt8}) at library.jl:48
mtlfunction_link(job::GPUCompiler.CompilerJob, compiled::NamedTuple{(:image, :entry), Tuple{Vector{UInt8}, String}}) at execution.jl:174
cached_compilation(cache::Dict{UInt64, Any}, job::GPUCompiler.CompilerJob, compiler::typeof(Metal.mtlfunction_compile), linker::typeof(Metal.mtlfunction_link)) at cache.jl:95
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}; name::Nothing, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}) at execution.jl:148
mtlfunction(f::typeof(generate), tt::Type{Tuple{MtlDeviceMatrix{RGB{N0f8}, 1}, Int64}}) at execution.jl:141
macro expansion at execution.jl:64 [inlined]
top-level scope at utilities.jl:10
eval at boot.jl:368 [inlined]
include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String) at loading.jl:1428
_include(mapexpr::Function, mod::Module, _path::String) at loading.jl:1488
include(mod::Module, _path::String) at Base.jl:419
exec_options(opts::Base.JLOptions) at client.jl:303
_start() at client.jl:522
**********************
from metal.jl.
Some small progress. (?)
In lib\mtl
, if I make all calls to unsafe_destroy!
a no-op, the seg-faults go away (though obviously leaking memory). So there is definitely something being double released.
If you look at the Metal Api for objects like: MTLCommandQueue, MTLCommandBuffer, MTLCommandBufferDescriptor, MTLComputeCommandEncoder, etc, you can notice a few things:
MTLCommandBufferDescriptor
has an option toretainedReferences
which is related to object ownership. (I tried setting totrue
andfalse
, neither seemed to fix to segfaults)- Objects like
MTLComputeCommandEncoder
come a fromMTLCommandBuffer
which may or may not be retaining a reference to the encoder.
It is possible that in Julia the objects are being finalized in an order that is incompatible with what is happening in the Objective-C runtime.
It seems like some next steps might be:
- Understand clearly how object ownership works with Metal in a pure Objective-C setting (or maybe be looking at Apple's c++ wrapper for Metal (basically a c++ equivalent for libcmt) to see how the destructors work there)
- Understand how object references are being recorded in Metal.jl
- Maybe come up with some way to test that there no leaks and also that references are not being prematurely lost/finalized
from metal.jl.
But another confusing thing is that I can only get the segfaults to occur when the Gtk4 main loop is running. If I create a version that does not involve Gtk4, there are no segfaults e.g.:
using Colors, FixedPointNumbers, Metal #Gtk4,
## Metal version of cpu.jl
function generate(img, pos)
r, c = Int32.(size(img))
i,j = thread_position_in_grid_2d()
@inbounds if i <= r && j <= c
img[i,j] = pos < j < pos + 10 ? colorant"red" : colorant"thistle"
end
return
end
img = MtlArray{RGB{N0f8}}(undef, 800,600)
wrapped = unsafe_wrap(Array{RGB{N0f8}}, img, size(img))
## initial image
println("init")
Metal.@sync @metal threads=16,16 grid=size(img) generate(img, 0)
println("window")
# win = GtkWindow("Test", 800, 600);
# data = reinterpret(Gtk4.GdkPixbufLib.RGB, wrapped) ## use unsafe_wrap after fixing segfault
# pixbuf = Gtk4.GdkPixbufLib.GdkPixbuf(data,false)
# view = GtkImage(pixbuf)
# push!(win,view)
# println("gtk4 main loop")
# if !isinteractive()
# @async Gtk4.GLib.glib_main()
# end
println("for loop")
for i=1:400
Metal.@sync @metal threads=16,16 grid=size(img) generate(img, i*2)
# Gtk4.G_.set_from_pixbuf(view, pixbuf)
GC.gc()
sleep(0.01)
end
println("wait")
#
# if !isinteractive()
# Gtk4.GLib.waitforsignal(win,:close_request)
# end
from metal.jl.
backtrace from lldb:
for loopProcess 6378 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x0000000101c881bc libjulia-internal.1.8.dylib`jl_exit_thread0_cb
libjulia-internal.1.8.dylib`jl_exit_thread0_cb:
-> 0x101c881bc <+0>: stp x20, x19, [sp, #-0x20]!
0x101c881c0 <+4>: stp x29, x30, [sp, #0x10]
0x101c881c4 <+8>: add x29, sp, #0x10
0x101c881c8 <+12>: mov x19, x0
Target 0: (julia) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
* frame #0: 0x0000000101c881bc libjulia-internal.1.8.dylib`jl_exit_thread0_cb
frame #1: 0x00000002026a32d4 libobjc.A.dylib
frame #2: 0x00000001b1ed9b64 libobjc.A.dylib`_objc_msgSend_uncached + 68
frame #3: 0x00000001b1ee0168 libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) + 196
frame #4: 0x00000001b1edc870 libobjc.A.dylib`objc_autoreleasePoolPop + 256
frame #5: 0x00000001b22e5c6c CoreFoundation`_CFAutoreleasePoolPop + 32
frame #6: 0x00000001b3201804 Foundation`-[NSAutoreleasePool drain] + 140
frame #7: 0x000000015fb5eab0 libgtk-4.1.dylib`gdk_macos_event_source_prepare + 80
frame #8: 0x000000015e5b4354 libglib-2.0.0.dylib`g_main_context_prepare + 516
frame #9: 0x000000015e5b4e10 libglib-2.0.0.dylib`g_main_context_iterate + 128
frame #10: 0x000000015e5b5074 libglib-2.0.0.dylib`g_main_context_iteration + 116
frame #11: 0x00000002a6e780ec
frame #12: 0x00000002a6e6c378
frame #13: 0x00000002a6e6c788
frame #14: 0x0000000101c47668 libjulia-internal.1.8.dylib`start_task + 184
(lldb)
Seems like their is some interaction with the auto-release pool -- todo: learn more about that
from metal.jl.
Related Issues (20)
- `fill!` for `Int8` errors when the value is negative
- Support for macOS Sonoma HOT 1
- Long stacktrace when trying to create Float64 rand arrays HOT 2
- allowscalar equivalent for Metal.jl HOT 2
- Equivalent of cuSparse - start with sparse matvec HOT 7
- MPS - Support for Convolutional Neural Network kernels
- sum(vector) allocates a lot and feels slow. HOT 2
- Better error message for mixing MtlArray and Array operations
- Compilation failure due to high register usage HOT 3
- Threadgroup atomics require all-atomic operation HOT 3
- KernelAbstractions: add Atomix back-end
- Define map! ? HOT 1
- Q: How to debug kernels - KA.@print?
- Crash during MTLDispatchListApply HOT 14
- Unable to compile trig functions through ForwardDiff HOT 4
- `symbol multiply defined!` Bug/crash on Julia master, fine on 1.10 HOT 1
- `log1p` fails on `MtlArray{Float32}` HOT 10
- When precompiling, UndefVarError: `CompilerConfig` not defined HOT 2
- Legalization errors with vectorized code HOT 3
- Use vkFFT for FFT support HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from metal.jl.