Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the codeobject pointer to idetify regions #105

Merged
merged 29 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
df41342
a first approach
AndreasGocht Jun 12, 2020
35daf29
special case, using the object pointer
AndreasGocht Jun 12, 2020
17fec66
adopt testcase
AndreasGocht Jun 12, 2020
30f6965
working state
AndreasGocht Jun 24, 2020
f991814
Merge remote-tracking branch 'origin/master' into issue-88
AndreasGocht Jun 24, 2020
d92c5d6
working with code pointer on profile
AndreasGocht Jun 24, 2020
df09265
address user regions with line numbers#
AndreasGocht Jun 24, 2020
b9e4887
update tests
AndreasGocht Jun 24, 2020
ecb1fdd
only create name when needed
AndreasGocht Jun 24, 2020
882d8c2
fix region and module order
AndreasGocht Jun 24, 2020
c01aa1f
extend the other instrumenters
AndreasGocht Jun 24, 2020
ec407c9
update README.md
AndreasGocht Jun 24, 2020
a396c80
autopep8
AndreasGocht Jun 24, 2020
fa506c1
Apply suggestions from code review
AndreasGocht Jul 6, 2020
fbdcffa
sperate user regions and instrumented or decorated regions
AndreasGocht Jul 15, 2020
09ff745
fix style
AndreasGocht Jul 15, 2020
5eb191d
back to ref
AndreasGocht Jul 15, 2020
ac703fd
region --> function_name
AndreasGocht Jul 15, 2020
e2ac3e8
&SCOREP_User_LastFileHandle --> NULL
AndreasGocht Jul 15, 2020
3c708ab
Update scorep/user.py
AndreasGocht Jul 15, 2020
8afb236
Update src/scorepy/events.cpp
AndreasGocht Jul 15, 2020
6cafede
Update src/scorepy/events.cpp
AndreasGocht Jul 15, 2020
a609531
Update src/scorepy/events.hpp
AndreasGocht Jul 15, 2020
9274ba9
Update src/scorepy/events.cpp
AndreasGocht Jul 15, 2020
646767b
remove optional arguments
AndreasGocht Jul 15, 2020
4793e03
restructure code, to make things more clear.
AndreasGocht Jul 15, 2020
0996309
codestyle
AndreasGocht Jul 15, 2020
05a4fe9
some doc
AndreasGocht Jul 15, 2020
e7f01a9
Merge remote-tracking branch 'origin/master' into issue-88
AndreasGocht Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ Please be aware the `--user` is always passed to Score-P, as this is needed for
## Not Working
* python multiprocessing
* Score-P does currently only support MPI or SHMEM. Any other multiprocessing approach cannot be traced.
* tracking `importlib.reload()`

# Acknowledgments
The European Union initially supported this work as part of the European Union’s Horizon 2020 project READEX (grant agreement number 671657).
5 changes: 3 additions & 2 deletions scorep/_instrumenters/scorep_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ def _globaltrace(self, frame, why, arg):
if why == 'call':
code = frame.f_code
modulename = get_module_name(frame)

if not code.co_name == "_unsetprofile" and not modulename[:6] == "scorep":
full_file_name = get_file_name(frame)
line_number = code.co_firstlineno
scorep._bindings.region_begin(modulename, code.co_name, full_file_name, line_number)
scorep._bindings.region_begin(modulename, code.co_name, full_file_name, line_number, code)
elif why == 'return':
code = frame.f_code
modulename = get_module_name(frame)
if not code.co_name == "_unsetprofile" and not modulename[:6] == "scorep":
scorep._bindings.region_end(modulename, code.co_name)
scorep._bindings.region_end(modulename, code.co_name, code)
4 changes: 2 additions & 2 deletions scorep/_instrumenters/scorep_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ def _globaltrace(self, frame, why, arg):
if not code.co_name == "_unsettrace" and not modulename[:6] == "scorep":
full_file_name = get_file_name(frame)
line_number = code.co_firstlineno
scorep._bindings.region_begin(modulename, code.co_name, full_file_name, line_number)
scorep._bindings.region_begin(modulename, code.co_name, full_file_name, line_number, code)
return self._localtrace
return None

def _localtrace(self, frame, why, arg):
if why == 'return':
code = frame.f_code
modulename = get_module_name(frame)
scorep._bindings.region_end(modulename, code.co_name)
scorep._bindings.region_end(modulename, code.co_name, code)
return self._localtrace
42 changes: 32 additions & 10 deletions src/methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <cstdint>
#include <scorep/SCOREP_User_Functions.h>

#include <iostream>

extern "C"
{

Expand All @@ -28,15 +30,26 @@ extern "C"
static PyObject* region_begin(PyObject* self, PyObject* args)
{
const char* module;
const char* region_name;
const char* region;
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
const char* file_name;
PyObject* identifier = nullptr;
std::uint64_t line_number = 0;

if (!PyArg_ParseTuple(args, "sssK", &module, &region_name, &file_name, &line_number))
if (!PyArg_ParseTuple(args, "sssK|O", &module, &region, &file_name, &line_number,
&identifier))
{
return NULL;

const std::string& region = scorepy::make_region_name(module, region_name);
scorepy::region_begin(region, module, file_name, line_number);
}

if (identifier == nullptr)
{
scorepy::region_begin(region, module, file_name, line_number);
}
else
{
scorepy::region_begin(region, module, file_name, line_number,
reinterpret_cast<std::uintptr_t>(identifier));
}

Py_RETURN_NONE;
}
Expand All @@ -47,13 +60,22 @@ extern "C"
static PyObject* region_end(PyObject* self, PyObject* args)
{
const char* module;
const char* region_name;
const char* region;
PyObject* identifier = nullptr;

if (!PyArg_ParseTuple(args, "ss", &module, &region_name))
if (!PyArg_ParseTuple(args, "ss|O", &module, &region, &identifier))
{
return NULL;

const std::string& region = scorepy::make_region_name(module, region_name);
scorepy::region_end(region);
}

if (identifier == nullptr)
{
scorepy::region_end(region, module);
}
else
{
scorepy::region_end(region, module, reinterpret_cast<std::uintptr_t>(identifier));
}

Py_RETURN_NONE;
}
Expand Down
18 changes: 9 additions & 9 deletions src/scorepy/cInstrumenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "pythonHelpers.hpp"
#include <algorithm>
#include <array>
#include <cstdint>
#include <string>

namespace scorepy
Expand Down Expand Up @@ -113,33 +114,32 @@ bool CInstrumenter::on_event(PyFrameObject& frame, int what, PyObject*)
{
case PyTrace_CALL:
{
const PyCodeObject& code = *frame.f_code;
const char* name = PyUnicode_AsUTF8(code.co_name);
const PyCodeObject* code = frame.f_code;
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
const char* name = PyUnicode_AsUTF8(code->co_name);
const char* module_name = get_module_name(frame);
assert(name);
assert(module_name);
// TODO: Use string_view/CString comparison?
if (std::string(name) != "_unsetprofile" && std::string(module_name, 0, 6) != "scorep")
{
const int line_number = code.co_firstlineno;
const auto& region_name = make_region_name(module_name, name);
const int line_number = code->co_firstlineno;
const auto file_name = get_file_name(frame);
region_begin(region_name, module_name, file_name, line_number);
region_begin(name, module_name, file_name, line_number,
reinterpret_cast<std::uintptr_t>(code));
}
break;
}
case PyTrace_RETURN:
{
const PyCodeObject& code = *frame.f_code;
const char* name = PyUnicode_AsUTF8(code.co_name);
const PyCodeObject* code = frame.f_code;
const char* name = PyUnicode_AsUTF8(code->co_name);
const char* module_name = get_module_name(frame);
assert(name);
assert(module_name);
// TODO: Use string_view/CString comparison?
if (std::string(name) != "_unsetprofile" && std::string(module_name, 0, 6) != "scorep")
{
const auto& region_name = make_region_name(module_name, name);
region_end(region_name);
region_end(name, module_name, reinterpret_cast<std::uintptr_t>(code));
}
break;
}
Expand Down
154 changes: 107 additions & 47 deletions src/scorepy/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,11 @@ struct region_handle

constexpr region_handle uninitialised_region_handle = region_handle();

static std::unordered_map<std::string, region_handle> regions;
static std::unordered_map<std::uintptr_t, region_handle> regions;
static std::unordered_map<std::string, std::uintptr_t> region_translations;
static std::unordered_map<std::string, region_handle> user_regions;
static std::unordered_map<std::string, region_handle> rewind_regions;

void region_begin(const std::string& region_name, std::string module, std::string file_name,
std::uint64_t line_number)
{
auto& region_handle = regions[region_name];

if (region_handle == uninitialised_region_handle)
{
SCOREP_User_RegionInit(&region_handle.value, NULL, &SCOREP_User_LastFileHandle,
region_name.c_str(), SCOREP_USER_REGION_TYPE_FUNCTION,
file_name.c_str(), line_number);
SCOREP_User_RegionSetGroup(region_handle.value,
std::string(module, 0, module.find('.')).c_str());
}
SCOREP_User_RegionEnter(region_handle.value);
}

/// Region names that are known to have no region enter event and should not report an error
/// on region exit
static const std::array<std::string, 2> EXIT_REGION_WHITELIST = {
Expand All @@ -52,45 +38,119 @@ static const std::array<std::string, 2> EXIT_REGION_WHITELIST = {
#endif
};

void region_end(const std::string& region_name)
void region_begin(const std::string& region, const std::string& module,
const std::string& file_name, const std::uint64_t line_number,
const std::uintptr_t& identifier)
{
const auto itRegion = regions.find(region_name);
if (itRegion != regions.end())
{
SCOREP_User_RegionEnd(itRegion->second.value);
}
else
auto& region_handle = regions[identifier];

if (region_handle == uninitialised_region_handle)
{
static region_handle error_region;
static SCOREP_User_ParameterHandle scorep_param = SCOREP_USER_INVALID_PARAMETER;
static bool error_printed = false;
auto& region_name = make_region_name(module, region);
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
auto it = user_regions.find(region_name);
if (it == user_regions.end())
{
SCOREP_User_RegionInit(&region_handle.value, NULL, &SCOREP_User_LastFileHandle,
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
region_name.c_str(), SCOREP_USER_REGION_TYPE_FUNCTION,
file_name.c_str(), line_number);

if (std::find(EXIT_REGION_WHITELIST.begin(), EXIT_REGION_WHITELIST.end(), region_name) !=
EXIT_REGION_WHITELIST.end())
SCOREP_User_RegionSetGroup(region_handle.value,
std::string(module, 0, module.find('.')).c_str());
}
else
{
return;
region_handle = it->second;
}
region_translations[region_name + std::to_string(line_number)] = identifier;
}
SCOREP_User_RegionEnter(region_handle.value);
}

void region_begin(const std::string& region, const std::string& module,
const std::string& file_name, const std::uint64_t line_number)
{
auto& region_name = make_region_name(module, region);
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
auto& region_handle = user_regions[region_name];

if (error_region.value == SCOREP_USER_INVALID_REGION)
if (region_handle == uninitialised_region_handle)
{
auto it_translation = region_translations.find(region_name + std::to_string(line_number));
if (it_translation == region_translations.end())
{
SCOREP_User_RegionInit(&error_region.value, NULL, &SCOREP_User_LastFileHandle,
"error_region", SCOREP_USER_REGION_TYPE_FUNCTION, "scorep.cpp",
0);
SCOREP_User_RegionSetGroup(error_region.value, "error");
}
SCOREP_User_RegionEnter(error_region.value);
SCOREP_User_ParameterString(&scorep_param, "leave-region", region_name.c_str());
SCOREP_User_RegionEnd(error_region.value);
SCOREP_User_RegionInit(&region_handle.value, NULL, &SCOREP_User_LastFileHandle,
region_name.c_str(), SCOREP_USER_REGION_TYPE_FUNCTION,
file_name.c_str(), line_number);

if (!error_printed)
SCOREP_User_RegionSetGroup(region_handle.value,
std::string(module, 0, module.find('.')).c_str());
}
else
{
std::cerr << "SCOREP_BINDING_PYTHON ERROR: There was a region exit without an enter!\n"
<< "SCOREP_BINDING_PYTHON ERROR: For details look for \"error_region\" in "
"the trace or profile."
<< std::endl;
error_printed = true;
region_handle = regions[it_translation->second];
}
}
SCOREP_User_RegionEnter(region_handle.value);
}

void region_end(const std::string& region, const std::string& module,
const std::uintptr_t& identifier)
{
const auto it_region = regions.find(identifier);
if (it_region != regions.end())
{
SCOREP_User_RegionEnd(it_region->second.value);
}
else
{
auto& region_name = make_region_name(module, region);
region_end_error_handling(region_name);
}
}

void region_end(const std::string& region, const std::string& module)
{
auto& region_name = make_region_name(module, region);
const auto it_region = user_regions.find(region_name);
if (it_region != user_regions.end())
{
SCOREP_User_RegionEnd(it_region->second.value);
}
else
{
region_end_error_handling(region_name);
}
}

void region_end_error_handling(const std::string& region_name)
{
static region_handle error_region;
static SCOREP_User_ParameterHandle scorep_param = SCOREP_USER_INVALID_PARAMETER;
static bool error_printed = false;

if (std::find(EXIT_REGION_WHITELIST.begin(), EXIT_REGION_WHITELIST.end(), region_name) !=
EXIT_REGION_WHITELIST.end())
{
return;
}

if (error_region.value == SCOREP_USER_INVALID_REGION)
{
SCOREP_User_RegionInit(&error_region.value, NULL, &SCOREP_User_LastFileHandle,
"error_region", SCOREP_USER_REGION_TYPE_FUNCTION, "scorep.cpp", 0);
SCOREP_User_RegionSetGroup(error_region.value, "error");
}
SCOREP_User_RegionEnter(error_region.value);
SCOREP_User_ParameterString(&scorep_param, "leave-region", region_name.c_str());
SCOREP_User_RegionEnd(error_region.value);

if (!error_printed)
{
std::cerr << "SCOREP_BINDING_PYTHON ERROR: There was a region exit without an enter!\n"
<< "SCOREP_BINDING_PYTHON ERROR: For details look for \"error_region\" in "
"the trace or profile."
<< std::endl;
error_printed = true;
}
}

void rewind_begin(std::string region_name, std::string file_name, std::uint64_t line_number)
Expand Down Expand Up @@ -136,15 +196,15 @@ void parameter_string(std::string name, std::string value)

void oa_region_begin(std::string region_name, std::string file_name, std::uint64_t line_number)
{
auto& handle = regions[region_name];
auto& handle = user_regions[region_name];
SCOREP_User_OaPhaseBegin(&handle.value, &SCOREP_User_LastFileName, &SCOREP_User_LastFileHandle,
region_name.c_str(), SCOREP_USER_REGION_TYPE_FUNCTION,
file_name.c_str(), line_number);
}

void oa_region_end(std::string region_name)
{
auto& handle = regions[region_name];
auto& handle = user_regions[region_name];
SCOREP_User_OaPhaseEnd(handle.value);
}

Expand Down
17 changes: 13 additions & 4 deletions src/scorepy/events.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#pragma once

#include <Python.h>
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved
#include <cstdint>
#include <string>

namespace scorepy
{
/// Combine the arguments into a region name
/// Return value is a statically allocated string to avoid memory (re)allocations
inline const std::string& make_region_name(const char* module_name, const char* name)
inline const std::string& make_region_name(const std::string& module_name, const std::string& name)
{
static std::string region;
region = module_name;
Expand All @@ -16,9 +17,17 @@ inline const std::string& make_region_name(const char* module_name, const char*
return region;
}

void region_begin(const std::string& region_name, std::string module, std::string file_name,
std::uint64_t line_number);
void region_end(const std::string& region_name);
void region_begin(const std::string& region, const std::string& module,
const std::string& file_name, const std::uint64_t line_number,
const std::uintptr_t& identifier);
void region_begin(const std::string& region, const std::string& module,
const std::string& file_name, const std::uint64_t line_number);

void region_end(const std::string& region, const std::string& module,
const std::uintptr_t& identifier);
void region_end(const std::string& region, const std::string& module);

void region_end_error_handling(const std::string& region_name);
AndreasGocht marked this conversation as resolved.
Show resolved Hide resolved

void rewind_begin(std::string region_name, std::string file_name, std::uint64_t line_number);
void rewind_end(std::string region_name, bool value);
Expand Down
Loading