Giter VIP home page Giter VIP logo

Comments (6)

maleadt avatar maleadt commented on May 25, 2024
  • 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.

habemus-papadum avatar habemus-papadum commented on May 25, 2024

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.

habemus-papadum avatar habemus-papadum commented on May 25, 2024

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.

habemus-papadum avatar habemus-papadum commented on May 25, 2024

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 to retainedReferences which is related to object ownership. (I tried setting to true and false, neither seemed to fix to segfaults)
  • Objects like MTLComputeCommandEncoder come a from MTLCommandBuffer 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.

habemus-papadum avatar habemus-papadum commented on May 25, 2024

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.

habemus-papadum avatar habemus-papadum commented on May 25, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.