# Making a Function FASTER!

**URL:** https://discourse.julialang.org/t/making-a-function-faster/50041
**Category:** New to Julia
**Tags:** question
**Created:** [November 12, 2020, 11:04am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041 "2020-11-12T11:04:25Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 11:04am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/1 "2020-11-12T11:04:26Z")

</div>

Hi everyone. I am new to Julia. Just started a week ago.

I am trying to do a Monte Carlo kind of code and these functions are a part of it.

```julia
function GetTime(ray0, F_Sp)
    Snodes=zeros(size(ray0,1),1); #iniciate variable
    #Loop to evaluate slowness
    for ri=1:size(ray0,1)
        Snodes[ri]=F_Sp(ray0[ri,1],ray0[ri,2],ray0[ri,3]);
    end
    #mean slowness in every path
    B=(Snodes[1:end-1].+Snodes[2:end]).*0.5;
    #Distance between nodes
    C=((diff(ray0[:,1]).*diff(ray0[:,1]))+(diff(ray0[:,2]).*diff(ray0[:,2]))+(diff(ray0[:,3]).*diff(ray0[:,3]))).^(1/2);
    #traveltime
    T=sum(B.*C);
    return T
end

```

```julia
function RayBender(ray0,dz,dray,zmax,dr,F_Sp)
    T0=GetTime(ray0, F_Sp);
movedz=dz*dray;
NCC=0;
while NCC<dr-2
    NCC=0;
    for p=2:dr-1
        #Bend a point of the ray up and down
        #Also get the travel time of each test
        rayz1=[ray0[1:p-1,3] ; ray0[p,3]+movedz; ray0[p+1:end,3]];
        #rayz1[rayz1.>zmax] .= zmax;
        T1=GetTime([collect(ray0[:,1]) collect(ray0[:,2]) collect(rayz1)],F_Sp);
        rayz2=[ray0[1:p-1,3] ; ray0[p,3]-movedz; ray0[p+1:end,3]];
        T2=GetTime([collect(ray0[:,1]) collect(ray0[:,2]) collect(rayz2)],F_Sp);
        if T1<T0 && T1<T2 # If RAY 1 is the solution
            ray0=[collect(ray0[:,1]) collect(ray0[:,2]) collect(rayz1)];
            T0=T1;
            #println("T1")
        elseif T2<T0 && T2<T1 # If RAY 2 is the solution
            ray0=[collect(ray0[:,1]) collect(ray0[:,2]) collect(rayz2)];
            T0=T2;
            #println("T2")
        else
            NCC=NCC+1; # Keep Count of NO CHANGES
        end
    end
end
return T0,ray0

end

```

I have a path (ray) that crosses a box of velocity. F\_Sp is the interpolated 3D slowness function at any point.  
I need to call them like 2e14 times so i need it to be VERY FAST.

Can any one give me some tips?

The first one just calculates the travel time and the second one bends an initially linear ray into the real one.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 11:07am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/2 "2020-11-12T11:07:31Z")

</div>

Also. Can anyone tell me where is it faster for Julia to open a Function? Inside the code (beginning or end) or outside (in a separate file)?

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 12, 2020, 11:12am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/3 "2020-11-12T11:12:53Z")

</div>

First, please read: [PSA: how to quote code with backticks](https://discourse.julialang.org/t/psa-how-to-quote-code-with-backticks/7530)

Then, have you read through [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/)?

It has a lot of good advice, for this code, [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-views) should be especially useful.

> [@marianoarnaiz](#):
>
> Also. Can anyone tell me where is it faster for Julia to open a Function? Inside the code (beginning or end) or outside (in a separate file)?

It’s a bit unclear to me what this means. Putting code inside functions is a good idea, yes. Where the code exists (if it is in e.g. a file or the REPL) doesn’t matter for the performance of it.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 11:28am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/4 "2020-11-12T11:28:43Z")

</div>

Thanks for the reply! I did not know about these!

Regarding the function. I have these 2 at the very top of my main script. It bugs me a bit, but if they are at the end Julia won’t read them. I wonder it the will perform faster if I saved them outside my code as .jl files.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 12, 2020, 11:37am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/5 "2020-11-12T11:37:24Z")

</div>

> [@marianoarnaiz](#):
>
> Regarding the function. I have these 2 at the very top of my main script. It bugs me a bit, but if they are at the end Julia won’t read them. I wonder it the will perform faster if I saved them outside my code as .jl files.

They have to be defined before you try to run them. But exactly where they are defined doesn’t matter for performance, no.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 11:46am UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/6 "2020-11-12T11:46:16Z")

</div>

Thanks! I will try some of this right now

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [November 12, 2020, 2:47pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/7 "2020-11-12T14:47:07Z")

</div>

Forget everything you learned in Matlab or Python. Don’t try to “vectorize” everything. _Don’t_ allocate new arrays in innermost loops.

Start smaller: write a function that traces a single ray through a single path (if that is what you are doing), and ask for help in optimizing that. Give sample inputs so that your code is actually runnable.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 3:07pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/8 "2020-11-12T15:07:46Z")

</div>

Dear Kristoffer  
I tried some of the @ to make the code faste… now my Julia is Slow for everything. Any ideas what i dod wrong?

---

<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: [November 12, 2020, 3:12pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/9 "2020-11-12T15:12:42Z")

</div>

It’s really hard to tell without knowing what you did.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [November 12, 2020, 3:43pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/11 "2020-11-12T15:43:15Z")

</div>

> [@marianoarnaiz](#):
>
> Dear Kristoffer  
> I tried some of the @ to make the code faste… now my Julia is Slow for everything. Any ideas what i dod wrong?

I think you should go back to basic. Write down for yourself exactly what data a `Ray` needs to contain. Now write a `struct` that contains that. Now think about all operations you need to do on a `Ray` (check if it intersects something, compute a newly reflected ray etc etc). Implement those functions. Now you have a bunch of small stand alone functions. Now think about your full problem. You will have a vector of such `Ray`s. For each Ray, you do something,

So the code would, at a very high level, look something like:

```julia
struct Ray
    direction:: ...
end

struct Plane
    normal:: ...
end

function reflection(ray::Ray, plane::Plane)
    ....
end

function intersect(ray::Ray, plane::Plane)
    ....
end

struct Problem
    rays::Vector{Ray}
    planes::Vector{Plane}
end

function run_problem(p::Problem)
    for ray in p.rays
        for plane in p.planes
            if intersect(ray, plane)
                   # do something
             end
        end
    end
end

prob = Problem(
   [Ray(1.0, 0.0), ....],
   [Plane(0.0, 1.0), ...]
)

run_problem(prob)

```

It makes it easier if you think about what are the logical “parts” that make out the full program and try separate those out.

---

<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: [November 12, 2020, 6:54pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/12 "2020-11-12T18:54:16Z")

</div>

You are basically writing Matlab code, and thereby missing out on all the performance improvements you can get from Julia. In fact, your code would be quite inefficient in Matlab as well, because it creates a staggeringly massive amount of unnecessary arrays.

You should avoid all slices (`ray0[:, 1]`), and in particular you should remove absolutely every use of `collect`. Whenever you write `collect(ray0[:,2])` you create an unnecessary array, not once, but _twice_. A good rule of thumb is “never, never, ever use `collect`”. Out of 10000 times you use `collect`, 9999999999 times it’s wrong.

I have tried to translate your code into Julia. I cannot test it, because I lack your input data, so it may have bugs and may not even run, but you can see roughly how to speed your code up. I have removed some input arguments that seem to be redundant.

```julia
function proptime(ray, F)
    snode1 = F(ray[1, 1], ray[1, 2], ray[1, 3])
    time = zero(snode1)
    for i in 2:size(ray, 1)
        snode2 = F(ray[i, 1], ray[i, 2], ray[i, 3])
        B = (snode1 + snode2) / 2
        snode1 = snode2
        C = sqrt((ray[i, 1] - ray[i-1, 1])^2 + 
                 (ray[i, 2] - ray[i-1, 2])^2 + 
                 (ray[i, 3] - ray[i-1, 3])^2)
        time += B * C
    end
    return time
end

function bendray!(ray, F, Δz, zmax)
    t0 = proptime(F, ray)
    Nray = size(ray, 1)
    N = 0
    while N < Nray - 2
        N = 0
        for p in 2:Nray-1
            r3 = ray[p, 3]
            ray[p, 3] = r3 + Δz # just modify the existing array instead of making a completely new one
            # ray[p, 3] = min(r3 + Δz, zmax)
            t1 = proptime(F, ray)
            ray[p, 3] = r3 - Δz
            t2 = proptime(F, ray)
            if t1 < t0 && t1 < t2
                t0 = t1
                ray[p, 3] = r3 + Δz
            elseif t2 < t0
                t0 = t2
                ray[p, 3] = r3 - Δz
            else
                ray[p, 3] = r3
                N += 1
            end
        end
    end
    return t0, ray
end

```

This will only speed up the implementation of your algorithm, but the algorithm itself also looks _very_ inefficient, so you should probably re-write the whole thing from scratch and use a different algorithm

---

<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: [November 12, 2020, 8:07pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/13 "2020-11-12T20:07:00Z")

</div>

So, the thing about speeding up code is, you have to be lazy. Imagine that you are manually building the arrays, as if they were Lego buildings. You want to be fast by saving work.

If you want to see the effect of changing one piece in your Lego building, the efficient thing to do is to just replace that one brick.

Instead of doing that, your code is rebuilding the whole, or parts of, the building _18-24 times_ in _each iteration_. That’s pretty inefficient.

What’s more, after each brick change, what’s the lazy way of measuring the effect of that change? Your code finds the change by re-measuring the _entire_ building. That’s not efficient. In stead, just compare the parts of the building that were actually changed.

If you change one node in your ray, that affects two pieces of the whole ray. If the total number of pieces is small, it doesn’t matter, but if you have a _lot_ of pieces, then just compare the changes caused by those two ray pieces. (My code does _not_ implement this improvement, it just re-measures the whole thing each time.)

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 8:48pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/14 "2020-11-12T20:48:53Z")

</div>

Hi everyone! Thank you so much for the help.  
Coming from MATLAB is quite difficult for me not to see everything as vectors hahaha.  
Anyone can direct me to a book or website where I can see some none-matlab type codes?

THANKS AGAIN!

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 8:49pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/15 "2020-11-12T20:49:27Z")

</div>

Thanks man! I will try your suggestions.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 8:54pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/16 "2020-11-12T20:54:04Z")

</div>

Let me see if I can twist my problem this way. I also added a few @fastmath @simd and new Julia runs slow on everything I do… any clue?

---

<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: [November 12, 2020, 9:07pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/17 "2020-11-12T21:07:47Z")

</div>

My day job is also with Matlab. But you should do the same thing in Matlab, changing a single element is just fundamentally faster than creating dozens of copies over and over.

---

<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: [November 12, 2020, 9:09pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/18 "2020-11-12T21:09:29Z")

</div>

> [@marianoarnaiz](#):
>
> I also added a few `@fastmath` `@simd` and new Julia runs slow

Forget `@fastmath`, forget `@simd`. Fix the fundamentals.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 9:35pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/19 "2020-11-12T21:35:26Z")

</div>

I get it. I don’t know what I did… I made the whole code slower somehow trying to fix it hahaha. I will report back when I have a better version! Thanks for the ideas!

---

<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: [November 12, 2020, 10:05pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/20 "2020-11-12T22:05:52Z")

</div>

If it made sense to use them on everything, they’d be the default. It’s generally a bad idea to use ‘performance annotations’ that one doesn’t understand.

They’re also almost always for squeezing out the last bug of extra speed, but you’re not at that stage yet. There are large algorithmic changes you should be making first.

---

<div class="post-metadata">

### Author: ![marianoarnaiz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marianoarnaiz/32/19377_2.png) [@marianoarnaiz](https://discourse.julialang.org/u/marianoarnaiz)
#### Post date: [November 12, 2020, 11:32pm UTC](https://discourse.julialang.org/t/making-a-function-faster/50041/21 "2020-11-12T23:32:13Z")

</div>

Yeah! I get that!  
But I don’t know how… but using them made my Julia slow… I reinstalled it and now all is OK. Working on a better algorithm as we Speak!

[Next page](https://discourse.julialang.org/t/making-a-function-faster/50041.md?page=2)
