Mercurial > octave
view libinterp/corefcn/compile.cc @ 32307:02faaad763d4
VM Add support for echo
Introcudes flag in tree_evaluator that can be checked to see if echo, debug, VM profiler is enabled.
* libinterp/corefcn/compile.cc: Notify tree_evalutor VM profiler is active
* libinterp/parse-tree/pt-bytecode-vm.cc: Support echo, check new flag dbgprofecho
* libinterp/parse-tree/pt-bytecode-vm.h: New flag
* libinterp/parse-tree/pt-bytecode-walk.cc: 'Is script' flag for unwind data
* libinterp/parse-tree/pt-bytecode.h:
* libinterp/parse-tree/pt-eval.cc: Set dbgprofecho flag. Expose echo state to VM.
* libinterp/parse-tree/pt-eval.h:
author | Petter T. |
---|---|
date | Mon, 07 Aug 2023 10:10:49 +0200 |
parents | 56acd8f390f8 |
children | d8311055ebe1 |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2023 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include "ovl.h" #include "ov.h" #include "defun.h" #include "variables.h" #include "interpreter.h" #include "pt-bytecode-vm.h" #include "pt-bytecode-walk.h" OCTAVE_BEGIN_NAMESPACE(octave) // Cleverly hidden in pt-bytecode-vm.cc to prevent inlining here extern "C" void dummy_mark_1 (void); extern "C" void dummy_mark_2 (void); DEFUN (__dummy_mark_1__, , , doc: /* -*- texinfo -*- @deftypefn {} {} __dummy_mark_1__ () Dummy function that calls the c-function void dummy_mark_1 (void) that does nothing. Usefull for e.g. marking start and end for Callgrind analyzis or as an entry point for gdb. @end deftypefn */) { dummy_mark_1 (); return {}; } DEFUN (__dummy_mark_2__, , , doc: /* -*- texinfo -*- @deftypefn {} {} __dummy_mark_2__ () Dummy function that calls the c-function void dummy_mark_2 (void) that does nothing. Usefull for e.g. marking start and end for Callgrind analyzis or as an entry point for gdb. @end deftypefn */) { dummy_mark_2 (); return {}; } DEFUN (__vm_clear_cache__, , , doc: /* -*- texinfo -*- @deftypefn {} {@var{val} =} __vm_clear_cache__ () Internal function. @end deftypefn */) { octave::load_path::signal_clear_fcn_cache (); return octave_value {true}; } DEFUN (__vm_print_trace__, , , doc: /* -*- texinfo -*- @deftypefn {} {@var{prints_trace} =} __vm_print_trace__ ()) Internal function. Print a debug trace from the VM. Toggles on or off each call. There has to be a breakpoint set in some file for the trace to actually print anything. Returns true if a trace will be printed from now on, false otherwise. @end deftypefn */) { vm::m_trace_enabled = !vm::m_trace_enabled; return octave_value {vm::m_trace_enabled}; } DEFUN (__ref_count__, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{count} =} __ref_count__ (@var{obj})) Internal function. Returns reference count for an object. @end deftypefn */) { int nargin = args.length (); if (nargin != 1) print_usage (); octave_value ov = args (0); return octave_value {ov.get_count ()}; } DEFMETHOD (__vm_is_executing__, interp, , , doc: /* -*- texinfo -*- @deftypefn {} {@var{is_executing} =} __vm_is_executing__ ()) Internal function. Returns true if the VM is executing the function calling __vm_is_executing__ (). False otherwise. @end deftypefn */) { bool bytecode_running = interp.get_evaluator ().get_current_stack_frame ()->is_bytecode_fcn_frame (); return octave_value {bytecode_running}; } DEFMETHOD (__vm_profile__, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {} __vm_profile__ on @deftypefnx {} {} __vm_profile__ off @deftypefnx {} {} __vm_profile__ resume @deftypefnx {} {} __vm_profile__ clear @deftypefnx {} {@var{T} =} __vm_profile__ ("info") @deftypefnx {} {} __vm_profile__ Internal function. Profile code running in the VM. @table @code @item profile on Start the profiler, clearing all previously collected data if there is any. @item profile off Stop profiling. The collected data can later be retrieved and examined with @code{T = profile ("info")}. @item profile clear Clear all collected profiler data. @item profile resume Restart profiling without clearing the old data. All newly collected statistics are added to the existing ones. @item profile Toggles between profiling and printing the result of the profiler. Clears the profiler on each print. @item info Prints the profiler data. Not that output to a variable is not implemented yet. @end table @end deftypefn */) { int nargin = args.length (); auto &evaler = interp.get_evaluator (); std::string arg0; if (nargin >= 1) arg0 = args (0).string_value (); if (!arg0.size ()) { if (!vm::m_vm_profiler) { vm::m_vm_profiler = std::make_shared<vm_profiler> (); vm::m_profiler_enabled = true; evaler.vm_set_profiler_active (true); } else { evaler.vm_set_profiler_active (false); vm::m_profiler_enabled = false; auto p = vm::m_vm_profiler; vm::m_vm_profiler = nullptr; auto cpy = *p; cpy.print_to_stdout (); } } else if (arg0 == "on") { vm::m_profiler_enabled = false; vm::m_vm_profiler = std::make_shared<vm_profiler> (); vm::m_profiler_enabled = true; evaler.vm_set_profiler_active (true); } else if (arg0 == "resume") { if (!vm::m_vm_profiler) vm::m_vm_profiler = std::make_shared<vm_profiler> (); vm::m_profiler_enabled = true; evaler.vm_set_profiler_active (true); } else if (arg0 == "off") { evaler.vm_set_profiler_active (false); vm::m_profiler_enabled = false; } else if (arg0 == "clear") { evaler.vm_set_profiler_active (false); vm::m_profiler_enabled = false; vm::m_vm_profiler = nullptr; } else if (arg0 == "info") { auto p_vm_profiler = vm::m_vm_profiler; if (p_vm_profiler) { auto cpy = *p_vm_profiler; cpy.print_to_stdout (); } else warning ("Nothing recorded."); } else print_usage (); return octave_value {true}; } DEFMETHOD (__print_bytecode__, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{success} =} __print_bytecode__ (@var{fn_name})) Internal function. Prints the bytecode of a function, if any. @end deftypefn */) { int nargin = args.length (); if (nargin != 1) print_usage (); std::string fn_name = args(0).string_value (); symbol_table& symtab = interp.get_symbol_table (); octave_value ov = symtab.find_function (fn_name); if (!ov.is_defined ()) { error ("Function not defined: %s", fn_name.c_str ()); } octave_user_function *ufn = ov.user_function_value (); if (!ufn || (!ufn->is_user_function () && !ufn->is_user_script ())) { error ("Function not a user function or script: %s", fn_name.c_str ()); } if (!ufn->is_compiled () && V__enable_vm_eval__) compile_user_function (*ufn, 0); else if (!ufn->is_compiled ()) error ("Function not compiled: %s", fn_name.c_str ()); if (!ufn->is_compiled ()) error ("Function can't be compiled: %s", fn_name.c_str ()); auto bc = ufn->get_bytecode (); print_bytecode (bc); return octave_value {true}; } DEFMETHOD (__compile__, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{success} =} __compile__ (@var{fn_name}) @deftypefnx {} {@var{success} =} __compile__ (@var{fn_name}, "clear") @deftypefnx {} {@var{success} =} __compile__ (@var{fn_name}, "print") Compile the specified function to bytecode. The compiled function and its subfunctions will be executed by the VM when called. Returns true on success, otherwise false. The @qcode{"print"} option prints the bytecode after compilation. The @qcode{"clear"} option removes the bytecode from the function instead. @end deftypefn */) { int nargin = args.length (); if (! nargin) print_usage (); std::string fcn_to_compile; bool do_clear = false; bool do_print = false; for (int i = 0; i < nargin; i++) { auto arg = args(i); if (! arg.is_string()) error ("Non string argument"); std::string arg_s = arg.string_value (); if (i == 0) { fcn_to_compile = arg_s; continue; } if (arg_s == "clear") do_clear = true; if (arg_s == "print") do_print = true; } if (do_clear) { std::string name = fcn_to_compile; symbol_table& symtab = interp.get_symbol_table (); octave_value ov = symtab.find_function (name); if (!ov.is_defined ()) { error ("Function not defined: %s", name.c_str ()); } octave_user_function *ufn = ov.user_function_value (); if (!ufn || !ufn->is_user_function ()) { error ("Function not a user function: %s", name.c_str ()); } ufn->clear_bytecode (); return octave_value {true}; } { std::string name = fcn_to_compile; symbol_table& symtab = interp.get_symbol_table (); octave_value ov = symtab.find_function (name); if (!ov.is_defined ()) { error ("Function not defined: %s", name.c_str ()); } if (!ov.is_user_function () && !ov.is_user_script ()) { error ("Function is not a user function or script: %s", name.c_str ()); } octave_user_code *ufn = ov.user_code_value (); if (!ufn || (!ufn->is_user_function () && !ufn->is_user_script ())) { error ("Function is not really user function or script: %s", name.c_str ()); } // Throws on errors compile_user_function (*ufn, do_print); } return octave_value {true}; } // If TRUE, use VM evaluator rather than tree walker. // FIXME: Use OCTAVE_ENABLE_VM_EVALUATOR define to set it to true when // the VM has been tested properly. bool V__enable_vm_eval__ = false; DEFUN (__enable_vm_eval__, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {@var{val} =} __enable_vm_eval__ () @deftypefnx {} {@var{old_val} =} __enable_vm_eval__ (@var{new_val}) @deftypefnx {} {@var{old_val} =} __enable_vm_eval__ (@var{new_val}, "local") Query or set whether Octave automatically compiles functions to bytecode and executes them in a virtual machine (VM). Note that the virtual machine feature is experimental. The default value is currently false, while the VM is still experimental. Users need to explicitly call @code{__enable_vm_eval__ (1)} to enable it. In future, this will be set to the value of the OCTAVE_ENABLE_VM_EVALUATOR flag that was set when building Octave. When false, Octave uses a traditional tree walker to evaluate statements parsed from m-code. When true, Octave translates parsed statements to an intermediate representation that is then evaluated by a virtual machine. When called from inside a function with the @qcode{"local"} option, the setting is changed locally for the function and any subroutines it calls. The original setting is restored when exiting the function. Once compiled to bytecode, the function will always be evaluated by the VM no matter the state of @qcode{"__enable_vm_eval__"}, until the bytecode is cleared, by e.g. @qcode{"clear all"} or an modification to the function's m-file. @seealso{__compile__} @end deftypefn */) { return set_internal_variable (V__enable_vm_eval__, args, nargout, "__enable_vm_eval__"); } OCTAVE_END_NAMESPACE(octave)