JuliaLabs / Cassette.jl

Overdub Your Julia Code
Other
371 stars 35 forks source link

Overdubbing not working when function called from within `@threads for` loop #176

Open jwscook opened 4 years ago

jwscook commented 4 years ago

I've found that Cassette hasn't been able to overdub into loops parallelised with @threads. Below is my MWE, which shows how I've been using it. Interestingly it works with @spawn, so I will be able to find a workaround by @spawning and fetching the iterations of my loop instead of using @threads for.

using Cassette, Base.Threads, Test

original() = false
replacement() = true

Cassette.@context Ctx
Cassette.overdub(::Ctx, fn::typeof(original), args...) = replacement(args...)

const ctx = Ctx()

# sanity test
@test  Cassette.overdub(ctx, original)

# try it with @threads
function foo(testvalue)
  @threads for i in 1 # any number of iterations
   @test original() == testvalue
  end
end
foo(original()) # calling normally works
Cassette.overdub(ctx, foo, replacement()) # overdub doesn't work

# fetch appears to work - EDIT: no it doesn't
baz() = original()
task = Threads.@spawn Cassette.overdub(ctx, baz)
@test fetch(task)

The error I get is:

julia> Cassette.overdub(ctx, foo, replacement()) # overdub doesn't work
Test Failed at REPL[8]:4
  Expression: original() == testvalue
   Evaluated: false == true
ERROR: TaskFailedException:
There was an error during testing
Stacktrace:
 [1] call at /home/cookj/.julia/packages/Cassette/158rp/src/context.jl:456 [inlined]
 [2] fallback at /home/cookj/.julia/packages/Cassette/158rp/src/context.jl:454 [inlined]
 [3] overdub at /home/cookj/.julia/packages/Cassette/158rp/src/context.jl:280 [inlined]
 [4] wait at ./task.jl:267 [inlined]
 [5] threading_run at ./threadingconstructs.jl:34 [inlined]
 [6] overdub(::Cassette.Context{nametype(Ctx),Nothing,Nothing,Cassette.var"##PassType#256",Nothing,Nothing}, ::typeof(Base.Threads.threading_run), ::var"#102#threadsfor_fun#2"{Bool,Int64}) at /home/cookj/.julia/packages/Cassette/158rp/src/overdub.jl:0
 [7] macro expansion at ./threadingconstructs.jl:93 [inlined]
 [8] foo at ./REPL[8]:3 [inlined]
 [9] overdub(::Cassette.Context{nametype(Ctx),Nothing,Nothing,Cassette.var"##PassType#256",Nothing,Nothing}, ::typeof(foo), ::Bool) at /home/cookj/.julia/packages/Cassette/158rp/src/overdub.jl:0
 [10] top-level scope at REPL[10]:1

Is anyone able to shed any light on this?

Version info:

jwscook commented 4 years ago

This is a more accurate @spawn version of the @threads test

using Cassette, Base.Threads, Test

original() = false
replacement() = true

Cassette.@context Ctx
Cassette.overdub(::Ctx, fn::typeof(original), args...) = replacement(args...)

const ctx = Ctx()

function bar(testvalue)
  d = Dict()
  for i in 1
    d[i] = Threads.@spawn original()
  end
  for i in keys(d)
    @test fetch(d[i]) == testvalue
  end
end

bar(original())
Cassette.overdub(ctx, bar, replacement())

which also fails:

julia> Cassette.overdub(ctx, bar, replacement())
Test Failed at REPL[20]:7
  Expression: fetch(d[i]) == testvalue
   Evaluated: false == true
ERROR: There was an error during testing
vchuravy commented 4 years ago

This is probably #120