From 3f7095bbd9b1f6abcac3c64c8c9865fa8fce2246 Mon Sep 17 00:00:00 2001 From: gambas Date: Mon, 11 Mar 2019 16:34:50 +0100 Subject: [PATCH] Run JIT compilation in the background to make programs start faster. [INTERPRETER] * OPT: JIT compilation is run in two steps. [GB.JIT] * OPT: Run JIT compilation in the background. * NEW: JIT.Debug is a new property that allows to enable JIT debugging messages at runtime. --- main/gbx/gbx.c | 1 + main/gbx/gbx_c_process.c | 1 + main/gbx/gbx_class_load.c | 10 +- main/gbx/gbx_jit.c | 82 ++++++++---- main/gbx/gbx_jit.h | 3 +- main/lib/jit/gb.jit/.src/CCompilation.class | 121 ++++++++++++++++++ main/lib/jit/gb.jit/.src/Jit.module | 133 +++++++------------- 7 files changed, 232 insertions(+), 119 deletions(-) create mode 100644 main/lib/jit/gb.jit/.src/CCompilation.class diff --git a/main/gbx/gbx.c b/main/gbx/gbx.c index 1d8e6e6b5..c8f702aac 100644 --- a/main/gbx/gbx.c +++ b/main/gbx/gbx.c @@ -125,6 +125,7 @@ static void main_exit(bool silent) TRY { + JIT_abort(); SIGNAL_exit(); EXTERN_release(); STREAM_exit(); diff --git a/main/gbx/gbx_c_process.c b/main/gbx/gbx_c_process.c index d9294ad66..4524b51cd 100644 --- a/main/gbx/gbx_c_process.c +++ b/main/gbx/gbx_c_process.c @@ -1195,6 +1195,7 @@ END_PROPERTY BEGIN_METHOD(Process_Wait, GB_FLOAT timeout) + // FIXME: Does not work if Ignore is set CPROCESS_wait_for(THIS, (int)(VARGOPT(timeout, 0.0) * 1000)); END_METHOD diff --git a/main/gbx/gbx_class_load.c b/main/gbx/gbx_class_load.c index f4cf661d0..a733f25b2 100644 --- a/main/gbx/gbx_class_load.c +++ b/main/gbx/gbx_class_load.c @@ -1256,14 +1256,8 @@ static void load_without_inits(CLASS *class) ARCHIVE *arch = class->component ? class->component->archive : NULL; if (JIT_can_compile(arch)) - { - if (JIT_compile(arch)) - { - for(i = 0; i < class->load->n_func; i++) - class->load->func[i].fast = FALSE; - } - } - + JIT_compile(arch); + break; } } diff --git a/main/gbx/gbx_jit.c b/main/gbx/gbx_jit.c index 0ad636721..c7dbc26c1 100644 --- a/main/gbx/gbx_jit.c +++ b/main/gbx/gbx_jit.c @@ -43,6 +43,7 @@ bool JIT_disabled = FALSE; static bool _component_loaded = FALSE; static GB_FUNCTION _jit_compile_func; +static GB_FUNCTION _jit_wait_func; static bool _jit_compiling = FALSE; static void *_jit_library = NULL; @@ -56,32 +57,30 @@ void JIT_exit(void) ARRAY_delete(&_jit_func); } +void JIT_abort(void) +{ + static GB_FUNCTION _func; + + if (GB_GetFunction(&_func, CLASS_find_global("Jit"), "_Abort", NULL, NULL)) + ERROR_panic("Unable to find JIT._Abort() method"); + + GB_Call(&_func, 0, FALSE); +} + bool JIT_can_compile(ARCHIVE *arch) { return arch ? !arch->jit_compiling : !_jit_compiling; } -bool JIT_compile(ARCHIVE *arch) +void JIT_compile(ARCHIVE *arch) { - GB_VALUE *ret; - char *path; - void *lib; - void **iface; COMPONENT *current; if (JIT_disabled) - return TRUE; + return; - if (arch) - { - if (arch->jit_library) - return FALSE; - } - else - { - if (_jit_library) - return FALSE; - } + if (arch ? arch->jit_library : _jit_library) + return; if (!_component_loaded) { @@ -93,7 +92,7 @@ bool JIT_compile(ARCHIVE *arch) if (var && var[0] && !(var[0] == '0' && var[1] == 0)) { JIT_disabled = TRUE; - return TRUE; + return; } var = getenv("GB_JIT_DEBUG"); @@ -104,8 +103,10 @@ bool JIT_compile(ARCHIVE *arch) fprintf(stderr, "gbx3: loading gb.jit component\n"); COMPONENT_load(COMPONENT_create("gb.jit")); - if (GB_GetFunction(&_jit_compile_func, CLASS_find_global("Jit"), "_Compile", "s", "s")) - ERROR_panic("Unable to find JIT compilation method"); + if (GB_GetFunction(&_jit_compile_func, CLASS_find_global("Jit"), "_Compile", "s", "b")) + ERROR_panic("Unable to find JIT._Compile() method"); + if (GB_GetFunction(&_jit_wait_func, CLASS_find_global("Jit"), "_Wait", "s", "s")) + ERROR_panic("Unable to find JIT._Wait() method"); } arch ? (arch->jit_compiling = TRUE) : (_jit_compiling = TRUE); @@ -114,16 +115,39 @@ bool JIT_compile(ARCHIVE *arch) COMPONENT_current = NULL; GB_Push(1, T_STRING, arch ? arch->name : "", -1); - ret = GB_Call(&_jit_compile_func, 1, FALSE); - path = GB_ToZeroString((GB_STRING *)ret); + GB_Call(&_jit_compile_func, 1, FALSE); + + COMPONENT_current = current; +} + +bool wait_for_compilation(ARCHIVE *arch) +{ + COMPONENT *current; + void *lib; + void **iface; + GB_VALUE *ret; + char *path; + + if (JIT_disabled) + return TRUE; + + if (arch ? arch->jit_library : _jit_library) + return FALSE; + + current = COMPONENT_current; + COMPONENT_current = NULL; + + GB_Push(1, T_STRING, arch ? arch->name : "", -1); + ret = GB_Call(&_jit_wait_func, 1, FALSE); COMPONENT_current = current; - if (!*path) - ERROR_panic("Unable to compile JIT source file"); - arch ? (arch->jit_compiling = FALSE) : (_jit_compiling = FALSE); + path = GB_ToZeroString((GB_STRING *)ret); + if (!*path) + ERROR_panic("Unable to compile JIT source file"); + //fprintf(stderr, "gbx3: shared jit library is: %s\n", path); lib = dlopen(path, RTLD_NOW); @@ -157,6 +181,13 @@ static bool create_function(CLASS *class, int index) arch = class->component ? class->component->archive : NULL; + if (wait_for_compilation(arch)) + { + for (i = 0; i < class->load->n_func; i++) + class->load->func[i].fast = FALSE; + return TRUE; + } + func = &class->load->func[index]; func->fast_linked = TRUE; @@ -203,6 +234,7 @@ void JIT_exec(bool ret_on_stack) VALUE *sp = SP; JIT_FUNCTION *jit; CLASS *class = EXEC.class; + void *object = EXEC.object; char nparam = EXEC.nparam; VALUE ret; FUNCTION *func = EXEC.func; @@ -221,7 +253,7 @@ void JIT_exec(bool ret_on_stack) STACK_push_frame(&EXEC_current, func->stack_usage); CP = class; - OP = (void *)EXEC.object; + OP = object; FP = func; EC = NULL; diff --git a/main/gbx/gbx_jit.h b/main/gbx/gbx_jit.h index 60f895a88..9c992359c 100644 --- a/main/gbx/gbx_jit.h +++ b/main/gbx/gbx_jit.h @@ -38,7 +38,7 @@ typedef extern bool JIT_disabled; #endif -bool JIT_compile(ARCHIVE *arch); +void JIT_compile(ARCHIVE *arch); void JIT_debug(const char *fmt, ...); void JIT_exec(bool ret_on_stack); PCODE *JIT_get_code(FUNCTION *func); @@ -46,6 +46,7 @@ CLASS_CONST *JIT_get_constant(int index); void *JIT_get_class_ref(int index); void JIT_call_unknown(PCODE *pc, VALUE **psp); +void JIT_abort(void); void JIT_exit(void); bool JIT_can_compile(ARCHIVE *arch); diff --git a/main/lib/jit/gb.jit/.src/CCompilation.class b/main/lib/jit/gb.jit/.src/CCompilation.class new file mode 100644 index 000000000..6416bb2cf --- /dev/null +++ b/main/lib/jit/gb.jit/.src/CCompilation.class @@ -0,0 +1,121 @@ +' Gambas class file + +Static Public All As New Collection + +Static Private $sCompiler As String +Static Private $aFlags As String[] + +Public Name As String +Public PathSO As String + +Private $sResult As String +Private $fTime As Float +Private $hProcess As Process + +Static Private Sub Init() + + Dim sFlag As String + Dim sCompiler As String + + sCompiler = Env["GB_JIT_CC"] + If Not sCompiler Then sCompiler = "gcc" + + $sCompiler = System.Find(sCompiler) + If Not $sCompiler Then Error.Raise("Compiler not found") + + sFlag = Env["GB_JIT_CFLAGS"] + If Not sFlag Then sFlag = "-O3" + + $aFlags = Split(sFlag, " ") + +End + +Public Sub _new(sName As String, sPathSO As String, fTime As Float) + + Name = sName + PathSO = sPathSO + $fTime = fTime + All[sName] = Me + +End + +Public Sub Run(sInput As String, Optional sOutput As String, sOption As String) + + Dim aExec As String[] + 'Dim I As Integer + + If Not $sCompiler Then Init + + aExec = [$sCompiler] + If sOption Then aExec.Insert(Split(sOption, " ")) + aExec.Insert($aFlags) + aExec.Add(sInput) + If sOutput Then + aExec.Add("-o") + aExec.Add(sOutput) + Endif + + ' For I = 0 To aExec.Max + ' aExec[I] = Shell$(aExec[I]) + ' Next + + If Jit.Debug Then Error "gb.jit: run: "; aExec.Join(" ") + + $hProcess = Exec aExec For Read As "Compiler" + '$hProcess.Ignore = True + 'System._Breakpoint + +End + +Public Sub Compiler_Read() + + Dim sData As String + + sData = Read #$hProcess, -1024 + $sResult &= sData + +End + +Public Sub Compiler_Error(({Error}) As String) + + $sResult &= {Error} + +End + + +Public Sub Compiler_Kill() + + If $hProcess.Value = 0 Then + $fTime = Timer - $fTime + Jit._Time += $fTime + If Jit.Debug Then Error "gb.jit: compilation of '"; Name; "' done in "; Format($fTime, "0.000"); " s" + Else + If Jit.Debug Then Error "gb.jit: compilation of '"; Name; "' returns "; $hProcess.Value + Endif + + ' Shell "objdump -S " & Shell(sPathSO) To sResult + ' Error sResult + +End + +Public Sub Wait() As String + + If Jit.Debug Then Error "gb.jit: waiting for compilation of '"; Name; "'..." + $hProcess.Wait + + If Not Exist(PathSO) Then + Error "gb.jit: error: unable to compile JIT code of '"; Name; "':" + Error $sResult + Return + Endif + + Return PathSO + +End + +Public Sub Kill() + + Try $hProcess.Kill + $hProcess = Null + +End diff --git a/main/lib/jit/gb.jit/.src/Jit.module b/main/lib/jit/gb.jit/.src/Jit.module index 22d210379..3a5463bb2 100644 --- a/main/lib/jit/gb.jit/.src/Jit.module +++ b/main/lib/jit/gb.jit/.src/Jit.module @@ -4,87 +4,23 @@ Export Class __Jit Property Read Time As Float +Property Debug As Boolean + +Public _Time As Float -Private $fTime As Float -Private $sCompiler As String -Private $aFlags As String[] -Private $hProcess As Process -Private $sResult As String Private $bDebug As Integer -Private Sub Init() - - Dim sFlag As String - Dim sCompiler As String - - sCompiler = Env["GB_JIT_CC"] - If Not sCompiler Then sCompiler = "gcc" - - $sCompiler = System.Find(sCompiler) - If Not $sCompiler Then Error.Raise("Compiler not found") - - sFlag = Env["GB_JIT_CFLAGS"] - If Not sFlag Then sFlag = "-O3" - - $aFlags = Split(sFlag, " ") - -End - -Private Sub RunCompiler(sInput As String, Optional sOutput As String, sOption As String) As String - - Dim aExec As String[] - 'Dim I As Integer - - aExec = [$sCompiler] - If sOption Then aExec.Insert(Split(sOption, " ")) - aExec.Insert($aFlags) - aExec.Add(sInput) - If sOutput Then - aExec.Add("-o") - aExec.Add(sOutput) - Endif - - ' For I = 0 To aExec.Max - ' aExec[I] = Shell$(aExec[I]) - ' Next - - If $bDebug Then Error "gb.jit: run: "; aExec.Join(" ") - - $sResult = "" - $hProcess = Exec aExec For Read As "Compiler" - $hProcess.Wait - 'Shell aExec.Join(" ") & " 2>&1" To sResult - - Return $sResult - -End - -Public Sub Compiler_Read() - - Dim sData As String - - sData = Read #$hProcess, -1024 - $sResult &= sData - -End - -Public Sub Compiler_Error(({Error}) As String) - - $sResult &= {Error} - -End - -Public Sub _Compile(sArch As String) As String +Public Sub _Compile(sArch As String) As Boolean Dim sFile As String Dim sDir As String Dim sName As String Dim sPath As String Dim hFile As File - Dim sResult As String Dim sPathO As String Dim sPathSO As String Dim fTime As Float + Dim hComp As CCompilation fTime = Timer @@ -92,9 +28,6 @@ Public Sub _Compile(sArch As String) As String If $bDebug Then Error "gb.jit: translating "; If(sArch, sArch, "project") - If Not $sCompiler Then Init - - sName = sArch If Not sName Then sName = "gb" @@ -184,12 +117,10 @@ Public Sub _Compile(sArch As String) As String 'gcc -c -fPIC -o foo.o foo.c 'Exec [$sCompiler, "-c", "-fPIC", "-o", File.SetExt(sPath, "o"), sPath] To sResult 'Shell $sCompiler & " -c -fPIC " & sFlag & " -o " & Shell(sPathO) & " " & Shell(sPath) & " 2>&1" To sResult - sResult = RunCompiler(sPath, sPathSO, "-w -fPIC -shared -lm") - If Not Exist(sPathSO) Then - Error "gb.jit: error: unable to compile JIT code:" - Error sResult - Return - Endif + + hComp = New CCompilation(sName, sPathSO, fTime) + + hComp.Run(sPath, sPathSO, "-w -fPIC -shared -lm") ' If $bDebug Then Error "gb.jit: linking to "; sPathSO ' @@ -203,20 +134,52 @@ Public Sub _Compile(sArch As String) As String ' Return ' Endif - fTime = Timer - fTime - $fTime += fTime +End + +Public Sub _Wait(sArch As String) As String + + Dim hComp As CCompilation + Dim sResult As String - If $bDebug Then Error "gb.jit: done in "; Format(fTime, "0.000"); "s" + If Not sArch Then sArch = "gb" + hComp = CCompilation.All[sArch] + If Not hComp Then Return - ' Shell "objdump -S " & Shell(sPathSO) To sResult - ' Error sResult + sResult = hComp.Wait() + Return sResult + +End + +Public Sub _Abort() + + Dim hComp As CCompilation - Return sPathSO + If $bDebug Then Error "gb.jit: abort compilation" + + For Each hComp In CCompilation.All + hComp.Kill + Next + + CCompilation.All.Clear End + + Private Function Time_Read() As Float - Return $fTime + Return _Time + +End + +Private Function Debug_Read() As Boolean + + Return $bDebug + +End + +Private Sub Debug_Write(Value As Boolean) + + $bDebug = Value End