diff --git a/scorep/instrumenter.py b/scorep/instrumenter.py index 5ee0878..6fee6fb 100644 --- a/scorep/instrumenter.py +++ b/scorep/instrumenter.py @@ -1,6 +1,7 @@ import scorep.instrumenters.dummy import scorep.instrumenters.scorep_profile import scorep.instrumenters.scorep_trace +import scorep.instrumenters.scorep_profile_record global_instrumenter = None @@ -21,6 +22,9 @@ def get_instrumenter( if instrumenter_type == "profile": global_instrumenter = scorep.instrumenters.scorep_profile.ScorepProfile( bindings, enable_instrumenter) + elif instrumenter_type == "profile_record": + global_instrumenter = scorep.instrumenters.scorep_profile_record.ScorepProfileRecord( + bindings, enable_instrumenter) elif instrumenter_type == "trace": global_instrumenter = scorep.instrumenters.scorep_trace.ScorepTrace( bindings, enable_instrumenter) diff --git a/scorep/instrumenters/scorep_profile_record.py b/scorep/instrumenters/scorep_profile_record.py new file mode 100644 index 0000000..15ce662 --- /dev/null +++ b/scorep/instrumenters/scorep_profile_record.py @@ -0,0 +1,206 @@ +__all__ = ['ScorepProfileRecord'] +import sys +import inspect +import os.path +import atexit + +try: + import threading +except ImportError: + _setprofile = sys.setprofile + + def _unsetprofile(): + sys.setprofile(None) + +else: + def _setprofile(func): + threading.setprofile(func) + sys.setprofile(func) + + def _unsetprofile(): + sys.setprofile(None) + threading.setprofile(None) + + +class ScorepProfileRecord: + """Similar to ScorepProfile but disables recording, when instrumenter is disabled. + + """ + + def __init__(self, scorep_bindings, enable_instrumenter=True): + """ + @param enable_instrumenter true if the tracing shall be initialised. + Please note, that it is still possible to enable the tracing later using register() + """ + global global_instrumenter + global_instrumenter = self + self.tracer_registered = False + + self.scorep_bindings = scorep_bindings + self.globaltrace = self.globaltrace_lt + self.enable_instrumenter = enable_instrumenter + + if not self.enable_instrumenter: + self.scorep_bindings.disable_recording() + + def __del__(self): + if not self.scorep_bindings.recording_enabled(): + self.scorep_bindings.enable_recording() + + def register(self): + if not self.scorep_bindings.recording_enabled(): + self.scorep_bindings.enable_recording() + self.tracer_registered = True + _setprofile(self.globaltrace) + + def unregister(self): + _unsetprofile() + self.tracer_registered = False + if self.scorep_bindings.recording_enabled(): + self.scorep_bindings.disable_recording() + + def get_registered(self): + return self.tracer_registered + + def run(self, cmd): + self.runctx(cmd) + + def runctx(self, cmd, globals=None, locals=None): + if globals is None: + globals = {} + if locals is None: + locals = {} + if self.enable_instrumenter: + self.register() + try: + exec(cmd, globals, locals) + finally: + self.unregister() + + def runfunc(self, func, *args, **kw): + result = None + if self.enable_instrumenter: + self.register() + try: + result = func(*args, **kw) + finally: + self.unregister() + return result + + def globaltrace_lt(self, frame, why, arg): + """Handler for call events. + + If the code block being entered is to be ignored, returns `None', + else returns self.localtrace. + """ + if why == 'call': + code = frame.f_code + modulename = frame.f_globals.get('__name__', None) + if modulename is None: + modulename = "None" + if not code.co_name == "_unsetprofile" and not modulename[:6] == "scorep": + file_name = frame.f_globals.get('__file__', None) + if file_name is not None: + full_file_name = os.path.abspath(file_name) + else: + full_file_name = "None" + line_number = frame.f_lineno + self.scorep_bindings.region_begin( + modulename, code.co_name, full_file_name, line_number) + return + elif why == 'return': + code = frame.f_code + modulename = frame.f_globals.get('__name__', None) + if modulename is None: + modulename = "None" + if not code.co_name == "_unsetprofile" and not modulename[:6] == "scorep": + self.scorep_bindings.region_end(modulename, code.co_name) + else: + return + + def region_begin(self, module_name, function_name, file_name, line_number): + recording_enabled = self.scorep_bindings.recording_enabled() + if not recording_enabled: + self.scorep_bindings.enable_recording() + + self.scorep_bindings.region_begin( + module_name, function_name, file_name, line_number) + + if not recording_enabled: + self.scorep_bindings.disable_recording() + + def region_end(self, module_name, function_name): + recording_enabled = self.scorep_bindings.recording_enabled() + if not recording_enabled: + self.scorep_bindings.enable_recording() + + self.scorep_bindings.region_end(module_name, function_name) + + if not recording_enabled: + self.scorep_bindings.disable_recording() + + def rewind_begin(self, name, file_name=None, line_number=None): + """ + Begin of an Rewind region. If file_name or line_number is None, both will + bet determined automatically + @param name name of the user region + @param file_name file name of the user region + @param line_number line number of the user region + """ + if file_name is None or line_number is None: + frame = inspect.currentframe().f_back + file_name = frame.f_globals.get('__file__', None) + line_number = frame.f_lineno + if file_name is not None: + full_file_name = os.path.abspath(file_name) + else: + full_file_name = "None" + + self.scorep_bindings.rewind_begin(name, full_file_name, line_number) + + def rewind_end(self, name, value): + """ + End of an Rewind region. + @param name name of the user region + @param value True or False, whenether the region shall be rewinded or not. + """ + self.scorep_bindings.rewind_end(name, value) + + def oa_region_begin(self, name, file_name=None, line_number=None): + """ + Begin of an Online Access region. If file_name or line_number is None, both will + bet determined automatically + @param name name of the user region + @param file_name file name of the user region + @param line_number line number of the user region + """ + if file_name is None or line_number is None: + frame = inspect.currentframe().f_back + file_name = frame.f_globals.get('__file__', None) + line_number = frame.f_lineno + if file_name is not None: + full_file_name = os.path.abspath(file_name) + else: + full_file_name = "None" + + self.scorep_bindings.oa_region_begin(name, full_file_name, line_number) + + def oa_region_end(self, name): + self.scorep_bindings.oa_region_end(name) + + def user_enable_recording(self): + if self.tracer_registered: + self.scorep_bindings.enable_recording() + + def user_disable_recording(self): + if self.tracer_registered: + self.scorep_bindings.disable_recording() + + def user_parameter_int(self, name, val): + self.scorep_bindings.parameter_int(name, val) + + def user_parameter_uint(self, name, val): + self.scorep_bindings.parameter_string(name, val) + + def user_parameter_string(self, name, string): + self.scorep_bindings.parameter_string(name, string) diff --git a/src/scorep.cpp b/src/scorep.cpp index 9aa46a4..237c3d5 100644 --- a/src/scorep.cpp +++ b/src/scorep.cpp @@ -31,7 +31,7 @@ void region_begin(const std::string& region_name, std::string module, std::strin SCOREP_User_RegionInit(&handle.value, NULL, &SCOREP_User_LastFileHandle, region_name.c_str(), SCOREP_USER_REGION_TYPE_FUNCTION, file_name.c_str(), line_number); - SCOREP_User_RegionSetGroup(handle.value, std::string(module,0,module.find('.')).c_str()); + SCOREP_User_RegionSetGroup(handle.value, std::string(module, 0, module.find('.')).c_str()); } SCOREP_User_RegionEnter(handle.value); } @@ -118,6 +118,13 @@ extern "C" return Py_None; } + static PyObject* recording_enabled(PyObject* self, PyObject* args) + { + + long state = SCOREP_User_RecordingEnabled(); + return PyBool_FromLong(state); + } + /** This code is not thread save. However, this does not matter as the python GIL is not * released. */ @@ -277,6 +284,8 @@ extern "C" { "oa_region_end", oa_region_end, METH_VARARGS, "exit an online access region." }, { "enable_recording", enable_recording, METH_VARARGS, "disable scorep recording." }, { "disable_recording", disable_recording, METH_VARARGS, "disable scorep recording." }, + { "recording_enabled", recording_enabled, METH_VARARGS, + "checks whether scorep recording is enabled." }, { "parameter_int", parameter_int, METH_VARARGS, "User parameter int." }, { "parameter_uint", parameter_uint, METH_VARARGS, "User parameter uint." }, { "parameter_string", parameter_string, METH_VARARGS, "User parameter string." },