Skip to content

Need @force_interpret? (PrecompileTools still broken) #57957

@timholy

Description

@timholy

In writing tests for the revamp of SnoopCompile, I'm noticing that with more complex workloads, PrecompileTools isn't working. Upon tracing the problem, it seems to be due to premature compilation of the full expression returned by @compile_workload. Specifically, in

julia> using PrecompileTools

julia> macroexpand(Main, quote
       @compile_workload begin
           InvalidA.callscallsf(1)                      # resolved callee
           InvalidA.alsocallsf(1)                       # resolved callee (different branch)
           InvalidA.invokesfs(1)                        # invoked callee
           InvalidA.callscallsfrta(1)                   # runtime-dispatched callee
           InvalidA.callsfrtr(1)
           InvalidA.callsfrts(1)
       end
       end)
quote
    #= REPL[2]:2 =#
    begin
        #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:85 =#
        if ccall(:jl_generating_output, PrecompileTools.Cint, ()) == 1 && (PrecompileTools).workload_enabled(Main) || (PrecompileTools).verbose[]
            #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:86 =#
            begin
                #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:77 =#
                (PrecompileTools).tag_newly_inferred_enable()
                #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:78 =#
                try
                    #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:79 =#
                    begin
                        #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:71 =#
                        begin
                            #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:72 =#
                            $(Expr(:meta, :force_compile))
                            #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:73 =#
                            begin
                                #= REPL[2]:3 =#
                                InvalidA.callscallsf(1)
                                #= REPL[2]:4 =#
                                InvalidA.alsocallsf(1)
                                #= REPL[2]:5 =#
                                InvalidA.invokesfs(1)
                                #= REPL[2]:6 =#
                                InvalidA.callscallsfrta(1)
                                #= REPL[2]:7 =#
                                InvalidA.callsfrtr(1)
                                #= REPL[2]:8 =#
                                InvalidA.callsfrts(1)
                            end
                        end
                    end
                finally
                    #= /home/tim/.julia/dev/PrecompileTools/src/workloads.jl:81 =#
                    (PrecompileTools).tag_newly_inferred_disable()
                end
            end
        end
    end
end

the intent is to call PrecompileTools.tag_newly_inferred_enable() before the block inside the try/finally gets compiled. Unfortunately, with the following Julia diff:

$ git diff
diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c
index e9f464b644..7607736fb2 100644
--- a/src/staticdata_utils.c
+++ b/src/staticdata_utils.c
@@ -93,6 +93,7 @@ static _Atomic(uint8_t) jl_tag_newly_inferred_enabled = 0;
  */
 JL_DLLEXPORT void jl_tag_newly_inferred_enable(void)
 {
+    jl_printf(JL_STDOUT, "Enabling tagging of newly inferred CodeInstances.\n");
     jl_atomic_fetch_add(&jl_tag_newly_inferred_enabled, 1);  // FIXME overflow?
 }
 /**
@@ -100,6 +101,7 @@ JL_DLLEXPORT void jl_tag_newly_inferred_enable(void)
  */
 JL_DLLEXPORT void jl_tag_newly_inferred_disable(void)
 {
+    jl_printf(JL_STDOUT, "Disabling tagging of newly inferred CodeInstances.\n");
     jl_atomic_fetch_add(&jl_tag_newly_inferred_enabled, -1);  // FIXME underflow?
 }

@@ -119,6 +121,9 @@ JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t* ci)
     if (!newly_inferred)
         return;
     uint8_t tag_newly_inferred = jl_atomic_load_relaxed(&jl_tag_newly_inferred_enabled);
+    jl_printf(JL_STDOUT, "Tagging newly inferred CodeInstance: %d\n",
+             (int)(tag_newly_inferred ? 1 : 0));
+    jl_(ci);
     if (tag_newly_inferred) {
         jl_method_instance_t *mi = jl_get_ci_mi((jl_code_instance_t*)ci);
         uint8_t miflags = jl_atomic_load_relaxed(&mi->flags);

it's quite clear from the log that this isn't happening:

...
Tagging newly inferred CodeInstance: 0
Core.CodeInstance(def=f(Signed) from f(Integer), owner=nothing, next=#<null>, min_world=0x0000000000000001, max_world=0x0000000000009f5e, rettype=Int64, exctype=Union{}, rettype_const=1, inferred=nothing, debuginfo=#<null>, edges=svec(), analysis_results=Base.Compiler.AnalysisResults(result=nothing, next=#<null>), ipo_purity_bits=0x000040e0, time_infer_total=0x0000, time_infer_cache_saved=0x0000, time_infer_self=0x0000, time_compile=0x0000, specsigflags=0x00, precompile=false, invoke=0x00007f8e136ea4a0, specptr=0x0000000000000000)
Tagging newly inferred CodeInstance: 0
Core.CodeInstance(def=callsfrts(Int64) from callsfrts(Any), owner=nothing, next=#<null>, min_world=0x0000000000009f57, max_world=0x0000000000009f5e, rettype=Int64, exctype=Any, rettype_const=1, inferred=nothing, debuginfo=#<null>, edges=svec(), analysis_results=Base.Compiler.AnalysisResults(result=nothing, next=#<null>), ipo_purity_bits=0x000040c1, time_infer_total=0x0000, time_infer_cache_saved=0x0000, time_infer_self=0x0000, time_compile=0x0000, specsigflags=0x00, precompile=false, invoke=0x0000000000000000, specptr=0x0000000000000000)
Enabling tagging of newly inferred CodeInstances.
Disabling tagging of newly inferred CodeInstances.
...

(note that callfrts is the last entry in the workload)

One possible fix would be to have a way to specify that the block should be run in the interpreter until it reaches the @force_compile. I'd be interested in any alternative proposals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions