# Speeding up my code

**URL:** <https://discourse.julialang.org/t/speeding-up-my-code/76915>\
**Category:** Performance\
**Created:** [February 22, 2022, 3:48pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915 "2022-02-22T15:48:43Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![nicob](https://avatars.discourse-cdn.com/v4/letter/n/ecccb3/32.png) [@nicob](https://discourse.julialang.org/u/nicob)\
**Post date:** [February 22, 2022, 3:48pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/1 "2022-02-22T15:48:44Z")

</div>

Hi, I’m quite new to Julia and I’m looking for suggestions to improve the performance of my code to hopefully beat the Python version. From these 2 functions do you see any margin of improvement?  
For example I’am trying to avoid allocations but I don’t think I can apply the method provided in this example [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/)

I appreciate any help.

```julia
function _logS(MF::AbsPL, m::Vector{Float64})
    δm, ml = MF.δm, MF.ml
    s = zeros(size(m)) # already ok for mask_upp
    mask_low = @. m <= ml
    mask_mid = @. (m > ml) & (m < (ml + δm))
    s[mask_mid] = @. -log1pexp( δm/(m[mask_mid]-ml) + δm/(m[mask_mid]-(ml+δm)) ) 
    s[mask_low] .= -Inf
    s
end

function _logC(MF::AbsBPL, m::Vector{Float64}, N=200)
    δm, ml = MF.δm, MF.ml 
    xx = sort(vcat(LinRange(ml, ml+δm+0.1*δm, N),
                            LinRange(ml+δm+0.1*δm+0.1, maximum(m), N)))  
    cdf = cumul_integrate(xx, exp.(_logpdfm2(MF, xx)), TrapezoidalFast())
    intcdf = LinearInterpolation(xx, cdf, extrapolation_bc = NaN)(m)
    -log.(intcdf)
end

function _logpdfm1(MF::AbsBrokenPLMF, m::Vector{Float64})
    α1, α2, ml, mu, m_break = MF.α1, MF.α2, MF.ml, MF.mu, MF.m_break
    res = fill(NaN, size(m))   
    mask_compute = @. (ml < m) & (m < mu)
    mm = m[mask_compute]
    res[mask_compute] = ifelse.(mm .< m_break, 
                                  (-α1 .* log.(mm)) .+ _logS(MF, mm), 
                                  (-α2 .* log.(mm)) .+ _logS(MF, mm) .+ (α2-α1)*log(m_break))
    res
end

```

---

<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:** [February 22, 2022, 3:57pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/2 "2022-02-22T15:57:09Z")

</div>

Step 1 here is to not try so hard to vectorize everything. For example, `_logS` can just be written as

```julia
function _logS(MF::AbsPL, m::Vector{Float64})
    δm, ml = MF.δm, MF.ml
    s = zeros(size(m)) # already ok for mask_upp
    for ind in eachindex(m)
        if m[ind] <= ml
            s[ind] = -Inf
        elseif m <m < (ml + δm)
            s[ind] = -log1pexp( δm/(m[mask_mid]-ml) + δm/(m[mask_mid]-(ml+δm))
        end
    end
end

```

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [February 22, 2022, 5:37pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/3 "2022-02-22T17:37:59Z")

</div>

In python, vectorization speeds things up because it allows the use of numpy. In julia, this isn’t necessary.

Python:

```julia
import numpy as np
from time import time

x = np.random.rand(10**7)
y = np.random.rand(10**7)

def vectorized(x, y):
    return x*x + y*y + x*y

def loop(x, y):
    [x*x + y*y + x*y for (x,y) in zip(x,y)]

t0 = time()
vectorized(x,y) # 0.24799013137817383
t1 = time()
vectorized(x,y) # 0.09563016891479492
t2 = time()

print(t1-t0)
print(t2-t1)

t0 = time()
loop(x,y) # 4.1851279735565186
t1 = time()
loop(x,y) # 4.027431964874268
t2 = time()

print(t1-t0)
print(t2-t1)

```

Juila:

```julia
x = rand(10^7)
y = rand(10^7)

vectorized(x, y) = x.*x .+ y.*y .+ x.*y

loop(x, y) = [x*x + y*y + x*y for (x,y) in zip(x,y)]

@time vectorized(x,y)
# 0.216033 seconds (462.89 k allocations: 99.817 MiB, 2.25% gc time, 50.76% compilation time)
@time vectorized(x,y)
# 0.189564 seconds (2 allocations: 76.294 MiB)

@time loop(x,y)
# 0.139699 seconds (300.01 k allocations: 92.649 MiB, 46.57% compilation time)
@time loop(x,y)
# 0.122678 seconds (2 allocations: 76.294 MiB)

```

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [February 22, 2022, 8:45pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/4 "2022-02-22T20:45:21Z")

</div>

Curious that the Python version is also slower the first time. What’s going on there?

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [February 23, 2022, 3:57pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/5 "2022-02-23T15:57:06Z")

</div>

I can’t really confirm Python slower for the first time, or only slightly slower sometimes, not always:

```julia
[..]
>>> x = np.random.rand(10**7); y = np.random.rand(10**7)

>>> t0 = time(); vectorized(x,y) # 0.14753150939941406
>>> t1 = time(); vectorized(x,y) # 0.1444408893585205

```

Note, I moved the `rand`s for x and y after the `def`s to minimize cache pollution, otherwise pasted the script into my Python 3.6 REPL, without running (while still defining) the `loop` code.

Python **does** compile (the script, but doesn’t store on disk, unlike for the dependencies/imports), and I assume, and my first guess was that Python has a slight TTFX/TTFP problem like Julia, just not as pronounced. Maybe the compiler is more aggressive in later Python version, and then the effect more pronounced.

Can @Lilith or anyone confirm, and post Python version used? Posting the same code, in her order I get:

```julia
>>> print(t1-t0)
0.16790056228637695
>>> print(t2-t1)
0.1561567783355713

```

Running, not from the REPL (while not in her order, but doesn’t the order doesn’t seem to matter much), I actually get a bit more speed (by 18% to 28%), and then in my fastest case, the first run is actually faster:

```julia
$ time python3.6 test2.py
0.11993026733398438
0.12186145782470703
7.87701678276062
7.849463939666748

real	0m16,466s
user	0m16,698s
sys	0m1,338s

```

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [February 23, 2022, 4:51pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/6 "2022-02-23T16:51:50Z")

</div>

> [@Palli](#):
>
> Can @Lilith or anyone confirm, and post Python version used? Posting the same code, in her order I get:

I wrote scripts and executed them from the commandline with `$ julia scipt.jl` and `$ python3 script.py`. I have `python --version` as `Python 3.9.5` and `julia --version` as `julia version 1.7.2`.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [February 23, 2022, 4:59pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/7 "2022-02-23T16:59:01Z")

</div>

Thanks, since your first run was 2.59x slower, very much unlike mine (on loaded or not loaded) machine, it certainly is intriguing. Can you check again, to see if just a fluke? I don’t have that version, and not on Windows if that matters. It could have been a transient spike, at least on Windows… or any OS really.

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [February 23, 2022, 5:40pm UTC](https://discourse.julialang.org/t/speeding-up-my-code/76915/8 "2022-02-23T17:40:25Z")

</div>

> [@Palli](#):
>
> Can you check again, to see if just a fluke?

```julia
x@X % python3 timing.py
0.2230987548828125
0.09320807456970215
4.175736904144287
4.076184272766113
x@X % python3 timing.py
0.14977812767028809
0.09485483169555664
4.096446990966797
4.113823890686035
x@X % python3 timing.py
0.1487128734588623
0.09010791778564453
4.22429895401001
4.2131569385528564

```

Where `timing.py` is a file with the code from [Speeding up my code - #3 by Lilith](https://discourse.julialang.org/t/speeding-up-my-code/76915/3)

I’m on a Mac.
