# Julia slower than Matlab & Python? No

**URL:** <https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128>\
**Category:** Performance\
**Tags:** economics, tensorflow, matlab, pytorch\
**Created:** [January 8, 2020, 11:57pm UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128 "2020-01-08T23:57:37Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)\
**Post date:** [January 8, 2020, 11:57pm UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/1 "2020-01-08T23:57:37Z")

</div>

A recent paper [ML Software & Hardware for Econ](https://0f2486b1-f568-477b-8307-dd98a6c77afd.filesusr.com/ugd/f9db9d_e30014e1da4e42649a446f539271a983.pdf) finds Julia is often slower than Matlab & Numpy.  
Code for [Option Pricing is here](https://github.com/vduarte/benchmarkingML/tree/master/LSMC).  
Code for [Dynamic Programming is here](https://github.com/vduarte/benchmarkingML/tree/master/Sovereign_Default).

Usually, [writing Julia code similarly leads to enormous speed-up](https://github.com/jesusfv/Comparison-Programming-Languages-Economics).  
How can we tweak their code for a more accurate comparison???

Update:  
**Dynamic Programming** : [Stefan](https://github.com/StefanKarpinski/benchmarkingML/blob/patch-1/Sovereign_Default/julia.jl), [Tim](https://github.com/timholy/benchmarkingML/blob/teh/faster/Sovereign_Default/julia.jl), [Mason](https://github.com/MasonProtter/benchmarkingML/blob/patch-1/Sovereign_Default/julia.jl) tweaked the code & Julia is faster than Matlab/Python/R. Julia is faster than C++ in all but the two smallest grids.

**Option Pricing** : if you replace the awkward vectorized parts of the code, w/ simpler more intuitive loops, the Julia code easily outperforms the others (except TF/PyTorch which I don’t have right now).

In the paper they also run PyTorch & TensorFlow on GPU.  
@Mason asks if anyone can speed this up w/ Julia on a GPU as well??? (I think this would be awesome bc Julia is known to be great on GPU…)

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [January 9, 2020, 12:03am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/2 "2020-01-09T00:03:00Z")

</div>

> Can this be correct???

It’s possible to write arbitrarily slow code in any language if you write the code in a sufficiently preserve way. In fact, it’s much easier to write slow code than fast code.

---

<div class="post-metadata">

**Author:** ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)\
**Post date:** [January 9, 2020, 12:07am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/3 "2020-01-09T00:07:50Z")

</div>

Yeah but it looks like [they tried to write the code similarly](https://github.com/vduarte/benchmarkingML/tree/master/Sovereign_Default) across languages.

Usually, [writing Julia code similarly leads to enormous speed-up](https://github.com/jesusfv/Comparison-Programming-Languages-Economics).  
There must be something wrong. It’d be great to let them know before they publish it soon.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [January 9, 2020, 12:21am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/4 "2020-01-09T00:21:27Z")

</div>

The code, with some comments of my part:

```julia
using DelimitedFiles, Statistics

# Load grid for log(y) and transition matrix
logy_grid = readdlm("logy_grid.txt")[:] 
Py = readdlm("P.txt")
#those 2 variables should be const

function main(nB=351, repeats=500)
    β = .953
    γ = 2.
    r = 0.017
    θ = 0.282
    ny = size(logy_grid, 1)

    Bgrid = LinRange(-.45, .45, nB)
    ygrid = exp.(logy_grid)

    ymean = mean(ygrid) .+ 0 * ygrid
    def_y = min(0.969 * ymean, ygrid)

    Vd = zeros(ny, 1)
    Vc = zeros(ny, nB)
    V = zeros(ny, nB)
    Q = ones(ny, nB) * .95

    y = reshape(ygrid, (ny, 1, 1))
    B = reshape(Bgrid, (1, nB, 1))
    Bnext = reshape(Bgrid, (1, 1, nB))

    zero_ind = Int(ceil(nB / 2))

    function u(c, γ) #add the broadcast in the call? 
        return c.^(1 - γ) / (1 - γ)
    end

    t0 = time()
    function iterate(V, Vc, Vd, Q)
        EV = Py * V #array created, it should be preallocated
        EVd = Py * Vd#array created
        EVc = Py * Vc#array created

        Vd_target = u(def_y, γ) + β * (θ * EVc[:, zero_ind] + (1 - θ) * EVd[:])
#calling a[:] allocates a new array
        Vd_target = reshape(Vd_target, (ny, 1))

        Qnext = reshape(Q, (ny, 1, nB))

        c = @. y .- Qnext .* Bnext .+ B #array created
        c[c .<= 0] = 1e-14 .+ 0 * c[c .<= 0]
        EV = reshape(EV, (ny, 1, nB))
        m = @. u(c, γ) .+ β * EV #array created
        Vc_target = reshape(maximum(m, dims=3), (ny, nB))

        Vd_compat = Vd * ones(1, nB) #array created
        default_states = float(Vd_compat .> Vc)
        default_prob = Py * default_states #array created
        Q_target = (1. .- default_prob) ./ (1 + r)

        V_target = max.(Vc, Vd_compat) #array created

        return V_target, Vc_target, Vd_target, Q_target

    end

    iterate(V, Vc, Vd, Q) # warmup
    t0 = time()
    for iteration in 1:repeats
        V, Vc, Vd, Q = iterate(V, Vc, Vd, Q)
    end
    t1 = time()
    out = (t1 - t0) / repeats

end

print(1000 * main(1351, 10))

```

In short, a great speedup can be achieved with just changing some calls with implace versions and preallocating the arrays before the iterate definition

---

<div class="post-metadata">

**Author:** ![aaowens](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaowens/32/12101_2.png) [@aaowens](https://discourse.julialang.org/u/aaowens)\
**Post date:** [January 9, 2020, 12:28am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/5 "2020-01-09T00:28:47Z")

</div>

It looks like this code is mostly matrix and vector operations, which explains how they have a PyTorch version. It’s not clear that Julia should be any better at this, especially since Matlab uses multithreading by default and Julia doesn’t except for BLAS operations.

---

<div class="post-metadata">

**Author:** ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)\
**Post date:** [January 9, 2020, 12:31am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/6 "2020-01-09T00:31:19Z")

</div>

I see. But does that help explain why Julia is outperformed by regular Python/numpy?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [January 9, 2020, 12:32am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/7 "2020-01-09T00:32:54Z")

</div>

> [@Albert\_Zevelev](#):
>
> regular Python

numpy is basically C, if the overhead of the python interperater is minimal, numpy should be as fast as C since it’s only ~function call slower

> **[GitHub - numpy/numpy: The fundamental package for scientific computing with...](https://github.com/numpy/numpy)**
>
> The fundamental package for scientific computing with Python. - GitHub - numpy/numpy: The fundamental package for scientific computing with Python.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [January 9, 2020, 12:42am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/8 "2020-01-09T00:42:02Z")

</div>

A cursory look through the code also suggests that they are using `1` in a bunch of places where `1.0` would be better. I’m not sure how much performance difference it makes here though.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [January 9, 2020, 2:55am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/9 "2020-01-09T02:55:17Z")

</div>

I don’t care to figure out exactly what they’re trying to do so I apologize for the half-hearted answer, but a lot of stuff there smells bad. This one in particular just seems poorly planned.

```julia
default_states = float(Vd_compat .> Vc)

```

Also, similar syntax is a pretty bad standard for equating similar levels of effort for each set of code. They should seriously think about using the number of lines of code as a better standard. Similar syntax only ensures easy reading and implementation for those that use that type of syntax.

P.S.  
Their R code is also less than spectacular but why bother optimizing R code?

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 9, 2020, 3:45am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/10 "2020-01-09T03:45:30Z")

</div>

Y’all are missing the big one and first thing to check: the code uses non-constant globals.

[https://github.com/vduarte/benchmarkingML/pull/1](https://github.com/vduarte/benchmarkingML/pull/1)

More speedup is certainly possible, but this is the big performance killer.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [January 9, 2020, 4:35am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/11 "2020-01-09T04:35:27Z")

</div>

I actually tried to make them global and saw no significant improvement.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 9, 2020, 5:11am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/12 "2020-01-09T05:11:11Z")

</div>

Do you mean `const`?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [January 9, 2020, 5:14am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/13 "2020-01-09T05:14:22Z")

</div>

yes, exactly as your pr,

```julia
10975.95670223236% # with const                                                                                                                                    

11052.845978736877%   

```

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 9, 2020, 5:16am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/14 "2020-01-09T05:16:39Z")

</div>

Strange.

---

<div class="post-metadata">

**Author:** ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)\
**Post date:** [January 9, 2020, 5:17am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/15 "2020-01-09T05:17:19Z")

</div>

They find similar results for option pricing:  
[https://github.com/vduarte/benchmarkingML/tree/master/LSMC](https://github.com/vduarte/benchmarkingML/tree/master/LSMC)  
I’m not sure if this also applies

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 9, 2020, 6:23am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/16 "2020-01-09T06:23:27Z")

</div>

Profiler shows that most of time is spent on broadcasting

`c = @. y .- Qnext .* Bnext .+ B`  
and  
`m = @. u(c, γ) .+ β * EV`

Maybe Julia’s broadcasting has more room for improvement?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 9, 2020, 6:25am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/17 "2020-01-09T06:25:25Z")

</div>

Why the double broadcasting? Both `.` and `@.`, I mean.

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 9, 2020, 6:27am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/18 "2020-01-09T06:27:03Z")

</div>

I tried with and without it. Without @. took about 10% more time.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 9, 2020, 7:20am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/19 "2020-01-09T07:20:07Z")

</div>

You should just use `@.`, then, not both.

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 9, 2020, 8:19am UTC](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128/20 "2020-01-09T08:19:15Z")

</div>

There seems to be some performance difference in broadcasting operation between Julia and numpy.

```julia
C = np.random.rand(256, 1351, 1351)

%%timeit
C**0.3

15.3 s ± 805 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

```

Compare to:

```julia
const C=rand(256, 1351, 1351)

@time C.^0.3 # second time calling

34.271383 seconds (8 allocations: 3.481 GiB, 0.01% gc time)

```

[Next page](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128.md?page=2)
