-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fmiReload and fmiLoad not thread-save #186
Comments
We will check this. PS: In the current release, you don't need to load the FMU multiple times for multithreading. Loading it once and use
|
Any news on this issue? My scripts are generating a bunch of segmentation faults when running on a single FMU in multiple threads and FMI.jl is reporting errors when I re-use a FMU on a different thread. So I can't let my scripts run over night, because they'll break most of the time. ERROR: LoadError: TaskFailedException
nested task error: AssertionError: ["No FMU instance allocated (in current thread with ID `18`), have you already called fmiInstantiate?"] |
Hm... I am using multithreading on a single FMU quite often. There is no need to load/unload the FMU in this operation mode multiple times. I do this not only for simulation, but also gradinet determination in NeuralFMUs. You should be able to load the FMU a single time (on the main thread), simulate it on different threads (monte carlo style) and being able to unload it after all threads finished (again on the main thread). I am working on an update for the multithreading tutorial. But there where multiple other ToDos the last months (speed, sensitivities, ...) |
So a typical workflow might look like: (1) load FMU (its a dynamic library, so its ok to just load it once) |
I think I found my issue. I was My mwe looks something like this: FMU from model HelloWorld "Simple hello world example"
Real x(start=1, fixed=true);
Real y;
Real z;
parameter Real a = -0.5;
equation
der(x) = a*x;
y = sin(x);
z = 2*abs(x);
end HelloWorld; generated with OpenModelica:
import FMI
import FMIImport
ENV["JULIA_DEBUG"] = "FMI,FMIIMport,FMICore"
function runAll()
fmuPath = "fmu/HelloWorld.fmu"
inputVars = ["x"]
outputVars = ["y", "z"]
nInputs = length(inputVars)
nOutputs = length(outputVars)
nVars = nInputs + nOutputs
fmu = FMI.fmiLoad(fmuPath)
Threads.@threads for _ in 1:Threads.nthreads()*10
@info "Thread $(Threads.threadid()) starting!"
comp = FMI.fmiInstantiate!(fmu; loggingOn = false, externalCallbacks=false)
FMI.fmiSetupExperiment(comp)
FMI.fmiEnterInitializationMode(comp)
FMI.fmiExitInitializationMode(comp)
# Set random data
row = Array{Float64}(undef, nVars)
row_vr = FMI.fmiStringToValueReference(fmu.modelDescription, vcat(inputVars,outputVars))
for _ in 1:10
row[1:nInputs] = rand(nInputs)
FMIImport.fmi2SetReal(comp, row_vr, row)
row[nInputs+1:end] .= FMIImport.fmi2GetReal(comp, row_vr[nInputs+1:end])
end
#FMI.fmiFreeInstance!(comp)
@info "Thread $(Threads.threadid()) finished!"
end
FMI.fmiUnload(fmu)
end Output:
|
Is this error FMU-specific? |
I couldn't reproduce the same issue, but with 2.0 VanDerPol FMU from https://github.com/modelica/Reference-FMUs and can trigger an error in import FMI
import FMIImport
function runAll()
fmuPath = "fmu/2.0/VanDerPol.fmu"
inputVars = ["x0", "x1"]
outputVars = ["x0", "x1"]
nInputs = length(inputVars)
nOutputs = length(outputVars)
nVars = nInputs + nOutputs
fmu = FMI.fmiLoad(fmuPath)
Threads.@threads for _ in 1:Threads.nthreads()*10
@info "Thread $(Threads.threadid()) starting!"
comp = FMI.fmiInstantiate!(fmu; loggingOn = false, externalCallbacks=false)
FMI.fmiSetupExperiment(comp)
FMI.fmiEnterInitializationMode(comp)
FMI.fmiExitInitializationMode(comp)
# Set random data
row = Array{Float64}(undef, nVars)
row_vr = FMI.fmiStringToValueReference(fmu.modelDescription, vcat(inputVars,outputVars))
for _ in 1:1000
row[1:nInputs] = rand(nInputs)
FMIImport.fmi2SetReal(comp, row_vr, row)
row[nInputs+1:end] .= FMIImport.fmi2GetReal(comp, row_vr[nInputs+1:end])
end
FMI.fmiFreeInstance!(comp)
@info "Thread $(Threads.threadid()) finished!"
end
FMI.fmiUnload(fmu)
end julia --threads=auto -e "include(\"runAllTheFMUs.jl\"); runAll()"
[ Info: Thread 10 finished!
ERROR: TaskFailedException
nested task error: AssertionError: fmi2FreeInstance!(...): Freeing 2 instances with one call, this is not allowed. Target address `Ptr{Nothing} @0x00007f2d0401a2a0` was found 2 times at indicies [6, 7].
Stacktrace:
[1] (::FMIImport.var"#78#80"{FMICore.FMU2Component{FMICore.FMU2}, Ptr{Nothing}})()
@ FMIImport ~/.julia/packages/FMIImport/hLBHK/src/FMI2/c.jl:126
[2] lock(f::FMIImport.var"#78#80"{FMICore.FMU2Component{FMICore.FMU2}, Ptr{Nothing}}, l::ReentrantLock)
@ Base ./lock.jl:229
[3] fmi2FreeInstance!(c::FMICore.FMU2Component{FMICore.FMU2}; popComponent::Bool)
@ FMIImport ~/.julia/packages/FMIImport/hLBHK/src/FMI2/c.jl:124
[4] fmi2FreeInstance!
@ ~/.julia/packages/FMIImport/hLBHK/src/FMI2/c.jl:117 [inlined]
[5] fmiFreeInstance!(str::FMICore.FMU2Component{FMICore.FMU2})
@ FMI ~/.julia/packages/FMI/1VUBe/src/deprecated.jl:75
[6] macro expansion
@ ~/workspace/Testitesttest/FMI-multithread/runAllTheFMUs.jl:39 [inlined]
[7] (::var"#6#threadsfor_fun#4"{var"#6#threadsfor_fun#3#5"{FMICore.FMU2, Int64, Int64, Vector{String}, Vector{String}, UnitRange{Int64}}})(tid::Int64; onethread::Bool)
@ Main ./threadingconstructs.jl:163
[8] #6#threadsfor_fun
@ ./threadingconstructs.jl:130 [inlined]
[9] (::Base.Threads.var"#1#2"{var"#6#threadsfor_fun#4"{var"#6#threadsfor_fun#3#5"{FMICore.FMU2, Int64, Int64, Vector{String}, Vector{String}, UnitRange{Int64}}}, Int64})()
@ Base.Threads ./threadingconstructs.jl:108
...and 1 more exception.
Stacktrace:
[1] threading_run(fun::var"#6#threadsfor_fun#4"{var"#6#threadsfor_fun#3#5"{FMICore.FMU2, Int64, Int64, Vector{String}, Vector{String}, UnitRange{Int64}}}, static::Bool)
@ Base.Threads ./threadingconstructs.jl:120
[2] macro expansion
@ ./threadingconstructs.jl:168 [inlined]
[3] runAll()
@ Main ~/workspace/Testitesttest/FMI-multithread/runAllTheFMUs.jl:21
[4] top-level scope
@ none:1 I need to run it multiple times to see the error. |
Maybe it's more of an OpenModelica issue. What are the requirements for the FMU to be simulated in parallel? |
I think thread-safety is definitely a hard requirement to simulate FMUs multi-threaded. However, the second issue ( |
Issue
I want to simulate a number of FMUs in parallel with FMI.jl and reuse the already loaded FMUs for multiple runs, but encounter an error in FMIImport where
cd
is used to change the directory while running in parallel.I believe the issue is the usage of
cd
in FMIImport ext.jl#L245-L252Is
cd
needed here? But I guess there are other problems with using e.g.ccall
in parallel, see https://docs.julialang.org/en/v1/manual/multi-threading/#@threadcall.If it's not possible to use
fmiLoad
andfmiReload
in parallel, maybe add a check to them to test if they are run inside a parallel region?How to reproduce
You can get similar results with
The text was updated successfully, but these errors were encountered: