Why the code recompiles?

When I am working with scientific projects, I am quite an old school guy who writes code and executes that with include("source.jl") in the Julia REPL. That had worked pretty well so far, but today I encountered a recompilation issue which makes my work less pleasant. A code which I execute with Julia 1.3 is:

using DifferentialEquations

struct PS{T}
   V::T
   VR::T
   r::T
   C::T
   Vext::Function
end

function phaseslip!(dq,q,p,t)
   V,VR,r,C,Vext = p.V, p.VR, p.r, p.C, p.Vext
   qL,qR = q[1],q[2]
   dq[1] = V - sin(qL) - 1/C * (qL - qR) - Vext(t)
   dq[2] = - VR * sin(qR) + r/C * (qL - qR) + r*Vext(t)
end

### Solving the system

p = PS(0.5,0.5,0.5,2.0,t->0.1*sin(t))

q0 = [0.,0.]
tspan = (0.0,2000)

prob = ODEProblem(phaseslip!,q0,tspan,p)
@time sol = solve(prob,dtmax=1.)

Every time I run it, I get 2.6 seconds. If I specifically execute the part after “Solving the system” I get 0.01 second. What is the reason for such behaviour? How can I avoid that?

This will slow your code down BTW. It’s better to parameterize that ::F

The using for DifferentialEquations.jl is probably a chunk of that. If you re-run with the REPL window still open it won’t have to keep using.

1 Like

When I comment out phaseslip! for repeated run it runs fast. using DifferentialEquations does not affect the rerun time in the REPL.

I will check if parallelization of F helps. But I really would prefer to keep Vext as that makes the system conceptually simple and general.

The parametrization of Vext did not help. The following code has the same problem:

using DifferentialEquations

struct PS{T}
    V::T
    VR::T
    r::T
    C::T
end

function phaseslip!(dq,q,p,t)
    V,VR,r,C = p.V, p.VR, p.r, p.C
    Vext(t) = 0.1*sin(t)
    qL,qR = q[1],q[2]
    dq[1] = V - sin(qL) - 1/C * (qL - qR) - Vext(t)
    dq[2] = - VR * sin(qR) + r/C * (qL - qR) + r*Vext(t)
end

### Solving the system

p = PS(0.5,0.5,0.5,2.0)

q0 = [0.,0.]
tspan = (0.0,2000)

prob = ODEProblem(phaseslip!,q0,tspan,p)
@time sol = solve(prob,dtmax=1.)

The solution for me would be something within the lines of the following code:

function interactiveinclude(fname,h)
    hnew = hash(readlines(fname))
    if hnew!=h
        @eval include($fname)
    end
    return hnew
end

#include("formulation.jl")
function interactiveinclude(fname)
    @eval begin
        isdefined(Main,:h) || (h = nothing)
        h = interactiveinclude($fname,h)
    end
end

interactiveinclude("formulation.jl")

A dirty fix but works as expected. Does anyone already have a package for that?

1 Like

I guess Revise.jl does something like that, but only for packages?

Yes, and it does that job quite well. I always use it when I develop packages. However, I am not sure if I do want to structure my research code as a package. Part of the reason being that I am still trying to sell Julia to my supervisor, who just figured out that it is a great idea to enforce Python on the group because everyone uses it. Commonality I think could help a lot.

BTW I really think that over-definition of a method should never happen if an exact definition of method or a type is already loaded.

Revise works great for individual scripts as well as for packages. See the includet function and the documentation here:

https://timholy.github.io/Revise.jl/stable/cookbook/#includet-usage-1

Note that if the problem is recompilation of methods that are actually being edited rather than package loading or recompilation of unchanged methods, first use after redefinition will still be slow.

3 Likes

Yes, you definitely want to do that. The main advantage is being able to commit the Manifest.toml to your version control repository, resulting an perfectly reproducible environment (as far as dependencies are concerned).

Once you start relying on it, this is one of those “how did I live without this?” features.

You should still be able to interface with code from others using one of the Python interop packages:

4 Likes

I changed structure of my code to the one of the package. Indeed I am thinking why I did not do that earlier :wink: It also fixed the issue of the recompilation as using MyModule always runs quick.

3 Likes