[Rd] JIT compiler does not compile closures with custom environments

Duncan Murdoch murdoch@dunc@n @end|ng |rom gm@||@com
Wed Aug 18 16:36:48 CEST 2021


Forgot to add:  you could define f_env like this to get it compiled:

f_env <- local({
   cmpfun(function(x) {
     for(i in 1:10000) x <- x + 1
     x
   })
})

Not as convenient as JIT, but it gets the job done...

Duncan Murdoch

On 18/08/2021 10:33 a.m., Duncan Murdoch wrote:
> On 18/08/2021 9:00 a.m., Taras Zakharko wrote:
>> I have encountered a behavior of R’s JIT compiler that I can’t quite figure out. Consider the following code:
>>
>>
>>      f_global <- function(x) {
>>        for(i in 1:10000) x <- x + 1
>>        x
>>      }
>>
>>      f_env <- local({
>>       function(x) {
>>         for(i in 1:10000) x <- x + 1
>>         x
>>       }
>>      })
>>
>>      compiler::enableJIT(3)
>>
>>     bench::mark(f_global(0), f_env(0))
>>     # 1 f_global(0)    103µs 107.61µs     8770.    11.4KB      0    4384     0
>>     # 2 f_env(0)       1.1ms   1.42ms      712.        0B     66.3   290    27
>>     
>> Inspecting the closures shows that f_global has been byte-compiled while f_env has not been byte-compiled. Furthermore, if I assign a new environment to f_global (e.g. via environment(f_global) <- new.env()), it won’t be byte-compiled either.
>>
>> However, if I have a function returning a closure, that closure does get byte-compiled:
>>
>>     f_closure <- (function() {
>>       function(x) {
>>         for(i in 1:10000) x <- x + 1
>>        x
>>      }
>>     })()
>>
>>     bench::mark(f_closure(0))
>>     # 1 f_closure(0)    105µs    109µs     8625.        0B     2.01  4284     1      497ms
>>
>> What is going on here? Both f_closure and f_env have non-global environments. Why is one JIT-compiled, but not the other? Is there a way to ensure that functions defined in environments will be JIT-compiled?
> 
> About what is going on in f_closure:  I think the anonymous factory
> 
> function() {
>         function(x) {
>           for(i in 1:10000) x <- x + 1
>          x
>        }
>       }
> 
> got byte compiled before first use, and that compiled its result.  That
> seems to be what this code indicates:
> 
>     f_closure <- (function() {
>     res <- function(x) {
>     for(i in 1:10000) x <- x + 1
>     x
>     }; print(res); res
>     })()
>     #> function(x) {
>     #> for(i in 1:10000) x <- x + 1
>     #> x
>     #> }
>     #> <bytecode: 0x7fb43ec3aa70>
>     #> <environment: 0x7fb441117ac0>
> 
> But even if that's true, it doesn't address the bigger question of why
> f_global and f_env are treated differently.
> 
> Duncan Murdoch
>



More information about the R-devel mailing list