Cara menghilangkan overhead JIT dalam executable Julia (dengan MWE)

9

Saya menggunakan PackageCompiler berharap untuk membuat executable yang menghilangkan overhead kompilasi just-in-time.

Dokumentasi menjelaskan bahwa saya harus mendefinisikan suatu fungsi julia_mainuntuk memanggil logika program saya, dan menulis "file snoop", sebuah skrip yang memanggil fungsi yang ingin saya kompilasi. Saya julia_mainmengambil argumen tunggal, lokasi file yang berisi data input untuk dianalisis. Jadi untuk menjaga hal-hal sederhana file pengintaian saya cukup membuat satu panggilan julia_maindengan file input tertentu. Jadi saya berharap melihat executable yang dihasilkan berjalan dengan baik dan cepat (tanpa overhead kompilasi) ketika dieksekusi terhadap file input yang sama

Namun sayang, bukan itu yang saya lihat. Dalam contoh baru Julia julia_mainmembutuhkan sekitar 74 detik untuk eksekusi pertama dan sekitar 4,5 detik untuk eksekusi berikutnya. File yang dapat dieksekusi membutuhkan sekitar 50 detik setiap kali dipanggil.

Penggunaan saya atas build_executablefungsi ini terlihat seperti ini:

julia> using PackageCompiler

julia> build_executable("d:/philip/source/script/julia/jsource/SCRiPTMain.jl",
                        "testexecutable",
                        builddir = "d:/temp/builddir4",
                        snoopfile = "d:/philip/source/script/julia/jsource/snoop.jl",
                        compile = "all",
                        verbose = true)

Pertanyaan:

  1. Apakah argumen di atas benar untuk mencapai tujuan saya yang dapat dieksekusi tanpa overhead JIT?
  2. Ada saran lain untuk saya?

Inilah yang terjadi dalam menanggapi panggilan itu build_executable. Garis dari Start of snoop file execution!ke End of snoop file execution!dipancarkan oleh kode saya.

Julia program file:
  "d:\philip\source\script\julia\jsource\SCRiPTMain.jl"
C program file:
  "C:\Users\Philip\.julia\packages\PackageCompiler\CJQcs\examples\program.c"
Build directory:
  "d:\temp\builddir4"
Executing snoopfile: "d:\philip\source\script\julia\jsource\snoop.jl"
Start of snoop file execution!
 Warning: The 'control file' contains the key 'InterpolateCovariance' with value 'true' but that is not supported. Pass a value of 'false' or omit the key altogether.
 @ ValidateInputs d:\Philip\Source\script\Julia\JSource\ValidateInputs.jl:685
Time to build model 20.058000087738037
Saving c:/temp/SCRiPT/SCRiPTModel.jls
Results written to c:/temp/SCRiPT/SCRiPTResultsJulia.json
Time to write file: 3620 milliseconds
Time in method runscript: 76899 milliseconds
End of snoop file execution!
[ Info: used 1313 out of 1320 precompile statements
Build static library "testexecutable.a":
  atexit_hook_copy = copy(Base.atexit_hooks) # make backup
# clean state so that any package we use can carelessly call atexit
empty!(Base.atexit_hooks)
Base.__init__()
Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
using REPL
Base.REPL_MODULE_REF[] = REPL
Mod = @eval module $(gensym("anon_module")) end
# Include into anonymous module to not polute namespace
Mod.include("d:\\\\temp\\\\builddir4\\\\julia_main.jl")
Base._atexit() # run all exit hooks we registered during precompile
empty!(Base.atexit_hooks) # don't serialize the exit hooks we run + added
# atexit_hook_copy should be empty, but who knows what base will do in the future
append!(Base.atexit_hooks, atexit_hook_copy)

Build shared library "testexecutable.dll":
  `'C:\Users\Philip\.julia\packages\WinRPM\Y9QdZ\deps\usr\x86_64-w64-mingw32\sys-root\mingw\bin\gcc.exe' --sysroot 'C:\Users\Philip\.julia\packages\WinRPM\Y9QdZ\deps\usr\x86_64-w64-mingw32\sys-root' -shared '-DJULIAC_PROGRAM_LIBNAME="testexecutable.dll"' -o testexecutable.dll -Wl,--whole-archive testexecutable.a -Wl,--no-whole-archive -std=gnu99 '-IC:\Users\philip\AppData\Local\Julia-1.2.0\include\julia' -DJULIA_ENABLE_THREADING=1 '-LC:\Users\philip\AppData\Local\Julia-1.2.0\bin' -Wl,--stack,8388608 -ljulia -lopenlibm -m64 -Wl,--export-all-symbols`
Build executable "testexecutable.exe":
  `'C:\Users\Philip\.julia\packages\WinRPM\Y9QdZ\deps\usr\x86_64-w64-mingw32\sys-root\mingw\bin\gcc.exe' --sysroot 'C:\Users\Philip\.julia\packages\WinRPM\Y9QdZ\deps\usr\x86_64-w64-mingw32\sys-root' '-DJULIAC_PROGRAM_LIBNAME="testexecutable.dll"' -o testexecutable.exe 'C:\Users\Philip\.julia\packages\PackageCompiler\CJQcs\examples\program.c' testexecutable.dll -std=gnu99 '-IC:\Users\philip\AppData\Local\Julia-1.2.0\include\julia' -DJULIA_ENABLE_THREADING=1 '-LC:\Users\philip\AppData\Local\Julia-1.2.0\bin' -Wl,--stack,8388608 -ljulia -lopenlibm -m64`
Copy Julia libraries to build directory:
  7z.dll
  BugpointPasses.dll
  libamd.2.4.6.dll
  libamd.2.dll
  libamd.dll
  libatomic-1.dll
  libbtf.1.2.6.dll
  libbtf.1.dll
  libbtf.dll
  libcamd.2.4.6.dll
  libcamd.2.dll
  libcamd.dll
  libccalltest.dll
  libccolamd.2.9.6.dll
  libccolamd.2.dll
  libccolamd.dll
  libcholmod.3.0.13.dll
  libcholmod.3.dll
  libcholmod.dll
  libclang.dll
  libcolamd.2.9.6.dll
  libcolamd.2.dll
  libcolamd.dll
  libdSFMT.dll
  libexpat-1.dll
  libgcc_s_seh-1.dll
  libgfortran-4.dll
  libgit2.dll
  libgmp.dll
  libjulia.dll
  libklu.1.3.8.dll
  libklu.1.dll
  libklu.dll
  libldl.2.2.6.dll
  libldl.2.dll
  libldl.dll
  libllvmcalltest.dll
  libmbedcrypto.dll
  libmbedtls.dll
  libmbedx509.dll
  libmpfr.dll
  libopenblas64_.dll
  libopenlibm.dll
  libpcre2-8-0.dll
  libpcre2-8.dll
  libpcre2-posix-2.dll
  libquadmath-0.dll
  librbio.2.2.6.dll
  librbio.2.dll
  librbio.dll
  libspqr.2.0.9.dll
  libspqr.2.dll
  libspqr.dll
  libssh2.dll
  libssp-0.dll
  libstdc++-6.dll
  libsuitesparseconfig.5.4.0.dll
  libsuitesparseconfig.5.dll
  libsuitesparseconfig.dll
  libsuitesparse_wrapper.dll
  libumfpack.5.7.8.dll
  libumfpack.5.dll
  libumfpack.dll
  libuv-2.dll
  libwinpthread-1.dll
  LLVM.dll
  LLVMHello.dll
  zlib1.dll
All done

julia> 

EDIT

Saya takut membuat contoh kerja minimal akan sulit, tetapi langsung saja:

TestBuildExecutable.jl mengandung:

module TestBuildExecutable

Base.@ccallable function julia_main(ARGS::Vector{String}=[""])::Cint
    @show sum(myarray())
    return 0
end

#Function which takes approx 8 seconds to compile. Returns a 500 x 20 array of 1s
function myarray()
    [1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1;
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1;

# PLEASE EDIT TO INSERT THE MISSING 496 LINES, EACH IDENTICAL TO THE LINE ABOVE!

     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1;
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1]
end

end #module

SnoopFile.jl mengandung:

module SnoopFile

currentpath = dirname(@__FILE__)
push!(LOAD_PATH, currentpath)
unique!(LOAD_PATH)

using TestBuildExecutable

println("Start of snoop file execution!")
TestBuildExecutable.julia_main()
println("End of snoop file execution!")

end # module

Dalam contoh baru Julia, julia_mainmembutuhkan 8,3 detik untuk eksekusi pertama dan setengah milidetik untuk eksekusi kedua:

julia> @time TestBuildExecutable.julia_main()
sum(myarray()) = 10000
  8.355108 seconds (425.36 k allocations: 25.831 MiB, 0.06% gc time)
0

julia> @time TestBuildExecutable.julia_main()
sum(myarray()) = 10000
  0.000537 seconds (25 allocations: 82.906 KiB)
0

Jadi selanjutnya saya sebut build_executable:

julia> using PackageCompiler

julia> build_executable("d:/philip/source/script/julia/jsource/TestBuildExecutable.jl",
                       "testexecutable",
                       builddir = "d:/temp/builddir15",
                       snoopfile = "d:/philip/source/script/julia/jsource/SnoopFile.jl",
                       verbose = false)
Julia program file:
  "d:\philip\source\script\julia\jsource\TestBuildExecutable.jl"
C program file:
  "C:\Users\Philip\.julia\packages\PackageCompiler\CJQcs\examples\program.c"
Build directory:
  "d:\temp\builddir15"
Start of snoop file execution!
sum(myarray()) = 10000
End of snoop file execution!
[ Info: used 79 out of 79 precompile statements
All done

Akhirnya, di Prompt Perintah Windows:

D:\temp\builddir15>testexecutable
sum(myarray()) = 1000

D:\temp\builddir15>

yang membutuhkan (oleh stopwatch saya) 8 detik untuk berjalan, dan dibutuhkan 8 detik untuk menjalankan setiap kali dijalankan, bukan hanya pertama kali. Ini konsisten dengan executable yang melakukan kompilasi JIT setiap kali dijalankan, tetapi file snoop dirancang untuk menghindarinya!

Informasi versi:

julia> versioninfo()
Julia Version 1.2.0
Commit c6da87ff4b (2019-08-20 00:03 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)
Environment:
  JULIA_NUM_THREADS = 8
  JULIA_EDITOR = "C:\Users\Philip\AppData\Local\Programs\Microsoft VS Code\Code.exe"
Philip Swannell
sumber

Jawaban:

1

Sepertinya Anda menggunakan Windows.

Pada titik tertentu PackageCompiler.jl akan matang untuk Windows di mana Anda dapat mencobanya.

Xiaodai
sumber
Terima kasih telah menunjukkannya. Saya menyadari PackageCompilerX, dan sangat menggembirakan untuk dicatat bahwa itu sedang dalam pengembangan aktif dengan rilis hari ini (11 Desember 19). Saya akan bereksperimen dengan itu, tetapi saya mungkin harus bersabar!
Philip Swannell
1

Solusinya memang menunggu kemajuan PackageCompilerX, seperti yang disarankan oleh @xiaodai.

Pada 10 Februari 2020 apa yang sebelumnya PackageCompilerXmenjadi baru (versi 1.0) PackageCompiler, dengan API yang berubah secara signifikan, dan dokumentasi yang lebih menyeluruh.

Secara khusus, MWE di atas ( bermutasi untuk API baru PackageCompiler) sekarang berfungsi dengan benar tanpa overhead JIT.

Philip Swannell
sumber