reactorlabs / rir

GNU General Public License v2.0
62 stars 18 forks source link

Repeated/multiple compilation issue #1266

Open skrynski opened 5 months ago

skrynski commented 5 months ago

Multiple/unnecessary compilation case. f gets compiled into rir before it is first executed. In the process, g's dispatch table is created and linked from f (so far so good). After the first invocation of f, a version specialized for int is compiled for function g.
Then next time f gets executed, compilation does not happen (since PIR_WARMUP=3 ). F runs bytecode, calls g, the specialized version for ints is used. Now f is called once more. Compilation for f triggers. We can see in the compilation output that it takes many compilation passes and runs to infer the right context to g. And, since during each iteration the compiler tries to compile a suitable version of g, it ends up compiling 4 different versions with varying degrees of specialization. This is only to end up with the one that was compiled at the very beginning (the one for ints). The reason this version gets also recompiled is because we're in a new compilation session and, since PIR code is not kept around across sessions, a StaticCall instruction will trigger compilation of its callee to be hopefully available later for inlining (which I disabled in this case). The only step that is skipped is the translation for PIR to native for the int version, since it realizes that there is already a native version in the dispatch table for such context.

I believe the slow convergence to get the right context for the arguments to g is connected to the presence of the for loop. This needs to be looked into. Also, even if inlining is disabled in the repro, this could happen in situations where there is a StaticCall but the inlinee cannot be inlined (there a many unsupported cases in Rsh). The recompilation of the right version of g might be avoided if we decided to keep PIR code around (maybe the compile server could help here).

Running the following script:


f <- function() {

    tot <- 0L

    g <- function(x) x + 1

    for (i in 1:100000) {
        tot <- tot + g(i)
    }

    tot
}

rir.compile(f)
rir.disassemble(f)
f()
f()
f()
f()

And the command line: PIR_OSR=0 PIR_WARMUP=3 PIR_DEBUG=PrintPirAfterOpt,PrintToStdout bin/R -f compTest.R

while inlining is disabled (to achieve that simply return true at inline.cpp):


    auto dontInline = [](Closure* cls) {    
        return true;

Output:

>
>
> f <- function() {
+
+     tot <- 0L
+
+     g <- function(x) x + 1
+
+     for (i in 1:100000) {
+         tot <- tot + g(i)
+     }
+
+
+     tot
+ }
>
> rir.compile(f)
function ()
{
    tot <- 0L
    g <- function(x) x + 1
    for (i in 1:1e+05) {
        tot <- tot + g(i)
    }
    tot
}
<bytecode: 0x563274117130>
> rir.disassemble(f)
== closure 0x563274eadd00 (env 0x5632730d9cd8) ==
== dispatch table 0x563274117160 ==
= version 0 (0x563274719eb8) =
[sigature] needsEnv
[type feedback version] 0
[flags]
[stats]    invoked: 0, time: 0ms, deopt: 0
0:
      0   push_  0L
      5   visible_
      6   stvar_cached_  tot{0}
     15   push_  <lst x=R_MissingArg>
     20   push_  <(rir::DispatchTable*)0x56327348cda0>
     25   push_  NULL
     30   close_
     31   stvar_cached_  g{1}
     40   push_  1
     45   visible_
     46   force_
     47   push_  100000
     52   visible_
     53   force_
     54   ; :(1, 100000)
          colon_input_effects_
     55   pop_
     56   swap_
     57   colon_cast_lhs_
     58   [ <?> ] Type#0
     63   ensure_named_
     64   swap_
     65   colon_cast_rhs_
     66   ensure_named_
     67   [ <?> ] Type#1
     72   dup2_
     73   ; NULL
          le_
     74   [ _ ] Test#0
     79   brfalse_  1
     84   push_  1L
     89   br_  2
1:
     94   push_  -1L
2:
     99   swap_
    100   pick_  2
    105   dup2_
    106   ; NULL
          ne_
    107   [ _ ] Test#1
    112   brfalse_  4
    117   dup_
    118   stvar_cached_  i{3}
    127   pull_  2
    132   ensure_named_
    133   ; NULL
          add_
    134   ldvar_cached_  tot{0}
    143   [ <?> ] Type#2
    148   ldfun_  g
    153   [ 0, <0>, valid  ] Call#0
    158   mk_promise_  0
    163   ; g(i)
          call_  1
    180   [ <?> ] Type#4
    185   ; +(tot, g(i))
          add_
    186   [ <?> ] Type#5
    191   stvar_cached_  tot{0}
3:
    200   dup2_
    201   ; NULL
          ne_
    202   brfalse_  4
    207   dup_
    208   stvar_cached_  i{3}
    217   pull_  2
    222   ensure_named_
    223   ; NULL
          add_
    224   ldvar_cached_  tot{0}
    233   [ <?> ] Type#6
    238   ldfun_  g
    243   [ 0, <0>, valid  ] Call#1
    248   mk_promise_  1
    253   ; g(i)
          call_  1
    270   [ <?> ] Type#8
    275   ; +(tot, g(i))
          add_
    276   [ <?> ] Type#9
    281   stvar_cached_  tot{0}
    290   br_  3
4:
    295   popn_  3
    300   ldvar_cached_  tot{0}
    309   [ <?> ] Type#10
    314   ret_

[Prom (index 0)]
0:
      0   ldvar_  i
      5   [ <?> ] Type#3
     10   ret_

[Prom (index 1)]
0:
      0   ldvar_  i
      5   [ <?> ] Type#7
     10   ret_
> f()

╞═══════════════════════════════╡  Compiling g  ╞══════════════════════════════╡
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch;NonRefl0,!Obj0,SimpleInt0********

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x56327333da60]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch;NonRefl0,!Obj0,SimpleInt0            │
│ Properties:  Eager, !Reflection, ForceOrd: 0                                 │
├────── PIR Version After Optimizations
g[0x56327333da60]
BB0
  goto BB1
BB1   <- [0]
  val?^           %1.0  = LdArg                    0
  int$-           %1.1  = Force!<lazy>       !vr   %1.0,    <int$->
  void                    Visible            v
  real$-          %1.3  = Add                vd    %1.1, 1, elided   <real$->
  void                    Return             l     %1.3

│ g[0x56327333da60]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
[1] 5000150000
> f()
[1] 5000150000
> f()

╞═══════════════════════════════╡  Compiling f  ╞══════════════════════════════╡
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch********
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch********
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch;NonRefl0********
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0,!Obj0********
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0,!Obj0,SimpleInt0********
declareVersion: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0********

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x563274720890]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0,!Obj0,SimpleInt0     │
│ Properties:  Eager, !Reflection, ForceOrd: 0                                 │
├────── PIR Version After Optimizations
g[0x563274720890]
BB0
  goto BB1
BB1   <- [0]
  val?~+          %1.0  = LdArg                    0
  int$-           %1.1  = Force!<lazy>             %1.0,    <int$->
  void                    Visible            v
  real$-          %1.3  = Add                vd    %1.1, 1, elided   <real$->
  void                    Return             l     %1.3

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x563274fd8570]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0,!Obj0                │
│ Properties:  Eager, ForceOrd: 0                                              │
├────── PIR Version After Optimizations
g[0x563274fd8570]
BB0
  goto BB1
BB1   <- [0]
  val?~+          %1.0  = LdArg                    0
  val+            %1.1  = Force!<lazy>             %1.0,    <int$->
  lgl$#-          %1.2  = IsType                   %1.1 isA int$-
  cp              %1.3  = Checkpoint                -> BB2 (default) | BB3 (if assume failed)
BB2   <- [1]
  void                    Assume             D     %1.2, %1.3 (Typecheck@0x563274719d58[Type#0])
  int$-           %2.1  = CastType           d     dn %1.1
  void                    Visible            v
  real$-          %2.3  = Add                vd    %2.1, 1, elided   <real$->
  void                    Return             l     %2.3
BB3   <- [1]
  env             e3.0  = (MkEnv)            l     x=%1.0, parent=?, context 1
  fs              %3.1  = FrameState         R     0x56327415aee0+9: [%1.1], env=e3.0
  void                    Deopt              !v    %3.1   !

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x56327480a090]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch;Eager0,NonRefl0                      │
│ Properties:  Eager, ForceOrd: 0                                              │
├────── PIR Version After Optimizations
g[0x56327480a090]
BB0
  goto BB1
BB1   <- [0]
  val?^           %1.0  = LdArg                    0
  val?            %1.1  = Force!<lazy>             %1.0,    <int$->
  lgl$#-          %1.2  = IsType                   %1.1 isA int$-
  cp              %1.3  = Checkpoint                -> BB2 (default) | BB3 (if assume failed)
BB2   <- [1]
  void                    Assume             D     %1.2, %1.3 (Typecheck@0x563274719d58[Type#0])
  int$-           %2.1  = CastType           d     dn %1.1
  void                    Visible            v
  real$-          %2.3  = Add                vd    %2.1, 1, elided   <real$->
  void                    Return             l     %2.3
BB3   <- [1]
  env             e3.0  = (MkEnv)            l     x=%1.0, parent=?, context 1
  fs              %3.1  = FrameState         R     0x56327415aee0+9: [%1.1], env=e3.0
  void                    Deopt              !v    %3.1   !

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x563274f196d0]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch;NonRefl0                             │
│ Properties:  Eager, ForceOrd: 0                                              │
├────── PIR Version After Optimizations
g[0x563274f196d0]
BB0
  goto BB1
BB1   <- [0]
  val?^           %1.0  = LdArg                    0
  val?            %1.1  = Force!<lazy>       !vrLd %1.0,    <int$->
  lgl$#-          %1.2  = IsType                   %1.1 isA int$-
  cp              %1.3  = Checkpoint                -> BB2 (default) | BB3 (if assume failed)
BB2   <- [1]
  void                    Assume             D     %1.2, %1.3 (Typecheck@0x563274719d58[Type#0])
  int$-           %2.1  = CastType           d     dn %1.1
  void                    Visible            v
  real$-          %2.3  = Add                vd    %2.1, 1, elided   <real$->
  void                    Return             l     %2.3
BB3   <- [1]
  env             e3.0  = (MkEnv)            l     x=%1.0, parent=?, context 1
  fs              %3.1  = FrameState         R     0x56327415aee0+9: [%1.1], env=e3.0
  void                    Deopt              !v    %3.1   !

┌──────────────────────────────────────────────────────────────────────────────┐
│ g[0x56327482b600]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch                                      │
│ Properties:  Eager, ForceOrd: 0                                              │
├────── PIR Version After Optimizations
g[0x56327482b600]
BB0
  goto BB1
BB1   <- [0]
  val?^           %1.0  = LdArg                    0
  env             e1.1  = (MkEnv)            l     x=%1.0, parent=?, context 1
  val?            %1.2  = Force!<lazy>       !vL   %1.0, e1.1   <int$->
  lgl$#-          %1.3  = IsType                   %1.2 isA int$-
  cp              %1.4  = Checkpoint                -> BB2 (default) | BB3 (if assume failed)
BB2   <- [1]
  void                    Assume             D     %1.3, %1.4 (Typecheck@0x563274719d58[Type#0])
  int$-           %2.1  = CastType           d     dn %1.2
  lgl$#-          %2.2  = IsEnvStub          R     , e1.1
  void                    Assume             D     %2.2, %1.4 (EnvStubMaterialized@0x563274719d58[Call#unknown])
  void                    Visible            v
  real$-          %2.5  = Add                vd    %2.1, 1, elided   <real$->
  void                    Return             l     %2.5
BB3   <- [1]
  fs              %3.0  = FrameState         R     0x56327415aee0+9: [%1.2], env=e1.1
  void                    Deopt              !v    %3.0   !

┌──────────────────────────────────────────────────────────────────────────────┐
│ f[0x563274f25840]                                                            │
│ Context: !ExpMi,CorrOrd,!TMany,Argmatch                                      │
│ Properties:  Eager                                                           │
├────── PIR Version After Optimizations
f[0x563274f25840]
BB0
  goto BB1
BB1   <- [0]
  env             e1.0  = MkEnv              l     parent=R_GlobalEnv, context 1
  cls             %1.1  = MkCls                    g, e1.0
  void                    StVar              lW    tot, 0L, e1.0
  void                    StVar              lW    g, %1.1, e1.0
  void                    StVar              lW    i, 1L, e1.0
  real$-          %1.5  = StaticCall         !vr   g[0x563274720890](1L) from %1.1 e1.0   <real$->
  cp              %1.6  = Checkpoint                -> BB2 (default) | BB10 (if assume failed)
BB2   <- [1]
  void                    Assume             D     true, %1.6 (Typecheck@0x563274719eb8[Type#4])
  real$-          %2.1  = Add                d     0L, %1.5, elided   <real$->
  void                    StVar              lW    tot, %2.1, e1.0
  goto BB3
BB10   <- [1]
  fs              %10.0 = FrameState         R     0x563274eaf3c0+180: [1L, 100001L, 2L, 0L, %1.5], env=e1.0
  void                    Deopt              !v    %10.0   !
BB3   <- [2, 8]
  real$-          %3.0  = Phi                      %2.1:BB2, %8.1:BB8
  int$-           %3.1  = Phi                      2L:BB2, %6.0:BB8
  lgl$-           %3.2  = Neq                d     100001L, %3.1, elided
  lgl$#-          %3.3  = Identical                %3.2, false
  void                    Branch                   %3.3 -> BB9 (if true) | BB4 (if false)
BB9   <- [3]
  void                    Visible            v
  void                    Return             l     %3.0
BB4   <- [3]
  void                    StVar              lW    i, %3.1, e1.0
  cp              %4.1  = Checkpoint                -> BB6 (default) | BB5 (if assume failed)
BB6   <- [4]
  int$-           %6.0  = Add                d     %3.1, 1L, elided
  val?^ | miss    %6.1  = LdVar              eR    g, e1.0
  lgl$#-          %6.2  = Identical                %6.1, %1.1
  void                    Assume             D     %6.2, %4.1 (CallTarget@0x563274719eb8[Call#1])
  real$-          %6.4  = StaticCall         !vr   g[0x563274720890](%3.1) from %1.1 e1.0   <real$->
  cp              %6.5  = Checkpoint                -> BB8 (default) | BB7 (if assume failed)
BB5   <- [4]
  fs              %5.0  = FrameState         R     0x563274eaf3c0+217: [1L, 100001L, %3.1], env=e1.0
  void                    Deopt              !v    %5.0   !
BB8   <- [6]
  void                    Assume             D     true, %6.5 (Typecheck@0x563274719eb8[Type#8])
  real$-          %8.1  = Add                d     %3.0, %6.4, elided   <real$->
  void                    StVar              lW    tot, %8.1, e1.0
  goto BB3
BB7   <- [6]
  fs              %7.0  = FrameState         R     0x563274eaf3c0+270: [1L, 100001L, %6.0, %3.0, %6.4], env=e1.0
  void                    Deopt              !v    %7.0   !

│ g[0x56327480a090]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
│ g[0x563274720890]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
│ g[0x563274f196d0]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
│ g[0x563274fd8570]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
│ g[0x56327482b600]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
│ f[0x563274f25840]                                                            │
└──────────────────────────────────────────────────────────────────────────────┘
[1] 5000150000
> f()
[1] 5000150000