# Fast 4D argmax

**URL:** <https://discourse.julialang.org/t/fast-4d-argmax/58566>\
**Category:** Performance\
**Tags:** tullio\
**Created:** [April 4, 2021, 6:10pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566 "2021-04-04T18:10:27Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 5, 2021, 4:53pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/21 "2021-04-05T16:53:48Z")

</div>

How about using

```julia
julia_assign("A", A)
julia_eval("whichmax5Dt(A)", "Julia")

```

This should help us evaluate transfer issues.

---

<div class="post-metadata">

**Author:** ![jroon](https://avatars.discourse-cdn.com/v4/letter/j/fbc32d/32.png) [@jroon](https://discourse.julialang.org/u/jroon)\
**Post date:** [April 5, 2021, 5:26pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/22 "2021-04-05T17:26:36Z")

</div>

@mkitti - great suggestion - here is my R code and results now:

```julia
# Make an array
n = 20 ; nx = 400 ; v = 40 ; d = 3 
array4d <- array( runif(n*nx*v*d ,-1,0),
                  dim = c(n, nx, v, d) )
#Assign to Julia
julia_assign("A", array4d)

microbenchmark:: microbenchmark(
  res1 <- which_max_4D(array4d),
  res2 <- julia_eval("whichmax4D1(A)", "R"),
  res3 <- julia_eval("whichmax4D2(A)", "R"),
  res4 <- julia_eval("whichmax4Dmap(A)", "R"),
  res5 <- julia_eval("whichmax4Dreduce(A)", "R"),
  res6 <- julia_eval("whichmax4Dtullio(A)", "R"),
  res7 <- julia_eval("whichmax4D5_leandro(A)", "R"),
  res8 <- julia_eval("whichmax4D5_elrod(A)", "R"),
  res9 <- julia_eval("whichmax4D6(A)", "R"),
  res10 <- whichmaxC(array4d), times=500)

```

 ![Screenshot 2021-04-05 at 19.23.18](https://global.discourse-cdn.com/julialang/original/3X/2/4/249e946df1de0ea0474ec90ecfead62460bf2aac.png)

Wow!! 😃

I also ran a benchmark on the `julia_assign` command:

 ![Screenshot 2021-04-05 at 19.24.27](https://global.discourse-cdn.com/julialang/original/3X/e/0/e0c200846dbcecfeebc082a5f94d801771ac276e.png)

Looks like you are right @mkitti - the slow part is moving the data from R to Julia

Edit: I ran it on an even bigger array also:

 ![Screenshot 2021-04-05 at 22.36.44](https://global.discourse-cdn.com/julialang/original/3X/6/f/6f728697fdcfb01fe39a7ca25f874bde3667294a.png)

---

<div class="post-metadata">

**Author:** ![Non-Contradiction](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/non-contradiction/32/2208_2.png) [@Non-Contradiction](https://discourse.julialang.org/u/Non-Contradiction)\
**Post date:** [April 5, 2021, 6:44pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/23 "2021-04-05T18:44:31Z")

</div>

The performance here is indeed dominated by array transformation. Typically, the time can be decomposed into three parts.

1. JuliaCall interface function time cost (`julia_call` on the order of 10 microsends, `julia_command` on the order of 100 microseconds).
2. data transfer time cost, which will be on the order of milliseconds for a large data set like this.
3. julia function time cost.

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [April 5, 2021, 7:13pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/24 "2021-04-05T19:13:30Z")

</div>

It should be possible to wrap the raw bits of the R array instead of converting/copying - this is already done [here](https://github.com/JuliaInterop/RCall.jl/blob/0b5e9f119008d3a8471833566745311df79101ff/src/methods.jl#L61-L65) in RCall.jl for R → Julia arrays.

---

<div class="post-metadata">

**Author:** ![Non-Contradiction](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/non-contradiction/32/2208_2.png) [@Non-Contradiction](https://discourse.julialang.org/u/Non-Contradiction)\
**Post date:** [April 5, 2021, 8:14pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/25 "2021-04-05T20:14:13Z")

</div>

Thanks for the information.  
The current implementation of JuliaCall is on the “safe” side, so users have little to worry about. I have thought about having something like `julia_unsafe_call` which does not do things like automatic type conversion/data copying. I will think more about the idea when I have more time on this.  
Another thing is that JuliaCall currently uses RCall.rcopy for data copying. I just noticed that the performance here seems to be magnitude slower than `copy` in julia. And in this case, the `rcopy` logic should be here: [RCall.jl/base.jl at 0b5e9f119008d3a8471833566745311df79101ff · JuliaInterop/RCall.jl · GitHub](https://github.com/JuliaInterop/RCall.jl/blob/0b5e9f119008d3a8471833566745311df79101ff/src/convert/base.jl#L47-L68)  
I’m wondering whether the performance for `rcopy` in this case can also be improved.

---

<div class="post-metadata">

**Author:** ![jroon](https://avatars.discourse-cdn.com/v4/letter/j/fbc32d/32.png) [@jroon](https://discourse.julialang.org/u/jroon)\
**Post date:** [April 5, 2021, 8:34pm UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/26 "2021-04-05T20:34:42Z")

</div>

That all sounds awesome! To give you my perspective on how I’d like to use JuliaCall → I’m fluent enough in R to be effective at getting my work tasks done quickly and dabble with making packages etc (nothing released yet), I expect it would take me a while to get to that level in Julia. But I would like to splash in snippets of Julia here and there were R is particularly slow, as opposed to writing large functions outright. I know many people use Rcpp in this way, but I’ve always found C++ to be utterly impenetrable for me. Learning Julia seems more achievable for me! So from that point of view, achieving blistering speed via a `julia_unsafe_call` for short functions sounds very appealing, but, I do understand why its something you need to think carefully about also! In any case JuliaCall is already an awesome package - thank you!

I must say, the response to my query here has been great and I’m blown away at all the options presented, and speeds that can be achieved - thank you all for the time you have put into this!

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 6, 2021, 1:06am UTC](https://discourse.julialang.org/t/fast-4d-argmax/58566/27 "2021-04-06T01:06:04Z")

</div>

To elaborate on the unsafe aspects, see the comment here:

> <https://github.com/JuliaInterop/RCall.jl/blob/0b5e9f119008d3a8471833566745311df79101ff/src/methods.jl#L43-L57>

The asymmetry of the transfers is immediately striking to me. I may be mistaken, but we do not see a lot of overhead of transferring the result from Julia to R. This suggests a strategy of starting with the variable on the Julia side.

Perhaps @randy3k or @simonbyrne could comment from the Rcall.jl perspective. I suspect `julia_[unsafe]_call` might not be that unsafe if `julia_call` could protect the data from R’s garbage collection. Some combination of `robject`, `RCall.protect`, and `unsafe_array` might work.

[Previous page](https://discourse.julialang.org/t/fast-4d-argmax/58566.md?page=1)
