2022-03-07 20:40:48 -06:00
|
|
|
// MIT License
|
|
|
|
|
//
|
2025-01-15 13:06:12 -05:00
|
|
|
// Copyright (c) 2022-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
2022-03-07 20:40:48 -06:00
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
// SOFTWARE.
|
|
|
|
|
|
|
|
|
|
#include "module_function.hpp"
|
2022-09-21 13:58:14 -05:00
|
|
|
#include "InstructionCategories.h"
|
2022-03-07 20:40:48 -06:00
|
|
|
#include "fwd.hpp"
|
2023-02-07 03:39:10 -06:00
|
|
|
#include "internal_libs.hpp"
|
2022-09-21 13:58:14 -05:00
|
|
|
#include "log.hpp"
|
2024-10-15 11:20:40 -04:00
|
|
|
#include "rocprof-sys-instrument.hpp"
|
2022-03-07 20:40:48 -06:00
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
#include <timemory/utility/join.hpp>
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
#include <stdexcept>
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
module_function::width_t&
|
|
|
|
|
module_function::get_width()
|
|
|
|
|
{
|
|
|
|
|
static width_t _instance = []() {
|
|
|
|
|
width_t _tmp;
|
|
|
|
|
_tmp.fill(0);
|
|
|
|
|
return _tmp;
|
|
|
|
|
}();
|
|
|
|
|
return _instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
module_function::reset_width()
|
|
|
|
|
{
|
|
|
|
|
get_width().fill(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
module_function::update_width(const module_function& rhs)
|
|
|
|
|
{
|
|
|
|
|
get_width()[0] = std::max<size_t>(get_width()[0], rhs.module_name.length());
|
|
|
|
|
get_width()[1] = std::max<size_t>(get_width()[1], rhs.function_name.length());
|
|
|
|
|
get_width()[2] = std::max<size_t>(get_width()[2], rhs.signature.get().length());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module_function::module_function(module_t* mod, procedure_t* proc)
|
|
|
|
|
: module{ mod }
|
|
|
|
|
, function{ proc }
|
2023-02-07 03:39:10 -06:00
|
|
|
, symtab_function{ proc->isInstrumentable() ? get_symtab_function(proc) : nullptr }
|
2022-03-07 20:40:48 -06:00
|
|
|
, flow_graph{ proc->getCFG() }
|
2022-07-21 01:15:41 -05:00
|
|
|
, module_name{ get_name(module) }
|
|
|
|
|
, function_name{ get_name(function) }
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
2024-10-15 11:20:40 -04:00
|
|
|
ROCPROFSYS_ADD_LOG_ENTRY("Adding function", function_name, "from module",
|
|
|
|
|
module_name);
|
2022-09-21 13:58:14 -05:00
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
if(!function->isInstrumentable())
|
|
|
|
|
{
|
2022-07-21 01:15:41 -05:00
|
|
|
verbprintf(1,
|
2022-03-07 20:40:48 -06:00
|
|
|
"Warning! module function generated for un-instrumentable "
|
|
|
|
|
"function: %s [%s]\n",
|
|
|
|
|
function_name.c_str(), module_name.c_str());
|
|
|
|
|
}
|
2022-07-21 01:15:41 -05:00
|
|
|
|
|
|
|
|
auto _range = std::pair<address_t, address_t>{};
|
2022-03-07 20:40:48 -06:00
|
|
|
if(function->getAddressRange(_range.first, _range.second))
|
2022-04-04 15:27:38 -05:00
|
|
|
{
|
|
|
|
|
start_address = _range.first;
|
2022-03-07 20:40:48 -06:00
|
|
|
address_range = _range.second - _range.first;
|
2022-04-04 15:27:38 -05:00
|
|
|
}
|
2022-07-21 01:15:41 -05:00
|
|
|
|
|
|
|
|
signature = get_func_file_line_info(module, function);
|
|
|
|
|
|
2022-09-21 13:58:14 -05:00
|
|
|
// make sure all exist
|
|
|
|
|
for(int i = 0; i <= instruction_category_t::c_NoCategory; ++i)
|
|
|
|
|
instruction_types[static_cast<instruction_category_t>(i)] = 0;
|
|
|
|
|
|
2022-07-21 01:15:41 -05:00
|
|
|
if(function->isInstrumentable())
|
|
|
|
|
{
|
|
|
|
|
// this information is potentially not available and
|
|
|
|
|
// appears to be the cause of a segfault in testing
|
|
|
|
|
// so only attempt to extract it for instrumentable
|
|
|
|
|
// functions
|
|
|
|
|
if(flow_graph)
|
|
|
|
|
{
|
|
|
|
|
flow_graph->getAllBasicBlocks(basic_blocks);
|
|
|
|
|
flow_graph->getOuterLoops(loop_blocks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instructions.reserve(basic_blocks.size());
|
2022-09-21 13:58:14 -05:00
|
|
|
size_t _n = 0;
|
2022-07-21 01:15:41 -05:00
|
|
|
for(const auto& itr : basic_blocks)
|
|
|
|
|
{
|
2022-09-21 13:58:14 -05:00
|
|
|
std::vector<std::pair<instruction_t, address_t>> _instructions{};
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if(itr->getInstructions(_instructions))
|
|
|
|
|
{
|
|
|
|
|
auto _num_instr = _instructions.size();
|
|
|
|
|
num_instructions += _num_instr;
|
|
|
|
|
for(auto&& iitr : _instructions)
|
|
|
|
|
{
|
|
|
|
|
instruction_types[iitr.first.getCategory()] += 1;
|
|
|
|
|
}
|
|
|
|
|
// num_instructions += _instructions.size();
|
|
|
|
|
if(debug_print || verbose_level > 3 || instr_print)
|
|
|
|
|
instructions.emplace_back(std::move(_instructions));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// on average, the number of instructions is address range / 4
|
|
|
|
|
auto _num_instr = (itr->getEndAddress() - itr->getStartAddress()) / 4;
|
|
|
|
|
verbprintf(2,
|
|
|
|
|
"No instructions found for basic block %zu in %s. "
|
|
|
|
|
"Approximating with %lu...\n",
|
|
|
|
|
_n, function_name.c_str(), _num_instr);
|
|
|
|
|
num_instructions += _num_instr;
|
|
|
|
|
}
|
|
|
|
|
} catch(std::runtime_error& _e)
|
|
|
|
|
{
|
|
|
|
|
errprintf(1, "Dyninst error: %s\n", _e.what());
|
|
|
|
|
}
|
|
|
|
|
++_n;
|
2022-07-21 01:15:41 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-03-07 20:40:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
module_function::write_header(std::ostream& os)
|
|
|
|
|
{
|
|
|
|
|
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
|
|
|
|
|
auto w1 = std::min<size_t>(get_width()[1], absolute_max_width);
|
|
|
|
|
auto w2 = std::min<size_t>(get_width()[2], absolute_max_width);
|
|
|
|
|
|
|
|
|
|
std::stringstream ss;
|
2022-04-04 15:27:38 -05:00
|
|
|
ss << std::setw(14) << "StartAddress"
|
|
|
|
|
<< " " << std::setw(14) << "AddressRange"
|
2022-03-07 20:40:48 -06:00
|
|
|
<< " " << std::setw(14) << "#Instructions"
|
|
|
|
|
<< " " << std::setw(6) << "Ratio"
|
2023-02-07 03:39:10 -06:00
|
|
|
<< " " << std::setw(7) << "Linkage"
|
|
|
|
|
<< " " << std::setw(10) << "Visibility"
|
2022-03-07 20:40:48 -06:00
|
|
|
<< " " << std::setw(w0 + 8) << std::left << "Module"
|
|
|
|
|
<< " " << std::setw(w1 + 8) << std::left << "Function"
|
|
|
|
|
<< " " << std::setw(w2 + 8) << std::left << "FunctionSignature"
|
|
|
|
|
<< "\n";
|
|
|
|
|
os << ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::should_instrument() const
|
2022-04-25 17:00:52 -05:00
|
|
|
{
|
|
|
|
|
return should_instrument(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::should_coverage_instrument() const
|
|
|
|
|
{
|
2022-05-08 01:40:56 -05:00
|
|
|
// hard constraints
|
|
|
|
|
if(!is_instrumentable()) return false;
|
|
|
|
|
if(!can_instrument_entry()) return false;
|
2023-02-07 03:39:10 -06:00
|
|
|
if(is_internal_constrained()) return false;
|
2022-05-08 01:40:56 -05:00
|
|
|
if(is_module_constrained()) return false;
|
|
|
|
|
if(is_routine_constrained()) return false;
|
|
|
|
|
|
|
|
|
|
// should be before user selection
|
|
|
|
|
constexpr int absolute_min_instructions = 2;
|
|
|
|
|
if(num_instructions < absolute_min_instructions)
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(
|
|
|
|
|
2, "Skipping", "function",
|
2022-06-10 06:57:50 -05:00
|
|
|
TIMEMORY_JOIN("-", "less-than", absolute_min_instructions, "instructions"),
|
|
|
|
|
function_name);
|
2022-05-08 01:40:56 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// user selection
|
|
|
|
|
if(is_user_excluded()) return false;
|
|
|
|
|
|
|
|
|
|
if(is_overlapping_constrained()) return false;
|
|
|
|
|
if(is_entry_trap_constrained()) return false;
|
|
|
|
|
|
|
|
|
|
// user selection
|
|
|
|
|
if(!file_restrict.empty() || !func_restrict.empty()) return !is_user_restricted();
|
|
|
|
|
if(is_user_included()) return true;
|
|
|
|
|
|
|
|
|
|
if(is_address_range_constrained()) return false;
|
|
|
|
|
if(is_num_instructions_constrained()) return false;
|
2023-02-07 03:39:10 -06:00
|
|
|
if(is_instruction_constrained()) return false;
|
2022-05-08 01:40:56 -05:00
|
|
|
|
|
|
|
|
return true;
|
2022-04-25 17:00:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::should_instrument(bool coverage) const
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
|
|
|
|
// hard constraints
|
|
|
|
|
if(!is_instrumentable()) return false;
|
|
|
|
|
if(!can_instrument_entry()) return false;
|
2022-04-25 17:00:52 -05:00
|
|
|
if(!coverage && !can_instrument_exit()) return false;
|
2023-02-07 03:39:10 -06:00
|
|
|
if(is_internal_constrained()) return false;
|
2022-03-07 20:40:48 -06:00
|
|
|
if(is_module_constrained()) return false;
|
|
|
|
|
if(is_routine_constrained()) return false;
|
|
|
|
|
|
|
|
|
|
// should be before user selection
|
2022-04-25 17:00:52 -05:00
|
|
|
constexpr int absolute_min_instructions = 2;
|
2022-03-07 20:40:48 -06:00
|
|
|
if(num_instructions < absolute_min_instructions)
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(
|
|
|
|
|
2, "Skipping", "function",
|
2022-06-10 06:57:50 -05:00
|
|
|
TIMEMORY_JOIN("-", "less-than", absolute_min_instructions, "instructions"),
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// user selection
|
|
|
|
|
if(is_user_excluded()) return false;
|
|
|
|
|
|
|
|
|
|
// should be applied before dynamic-callsite check
|
|
|
|
|
if(is_overlapping_constrained()) return false;
|
|
|
|
|
if(is_entry_trap_constrained()) return false;
|
2022-05-08 01:40:56 -05:00
|
|
|
if(!coverage && is_exit_trap_constrained()) return false;
|
2022-03-07 20:40:48 -06:00
|
|
|
|
|
|
|
|
// needs to be applied before address range and number of instruction constraints
|
|
|
|
|
if(is_dynamic_callsite_forced()) return true;
|
|
|
|
|
|
2022-04-25 17:00:52 -05:00
|
|
|
// user selection
|
|
|
|
|
if(!file_restrict.empty() || !func_restrict.empty()) return !is_user_restricted();
|
|
|
|
|
if(is_user_included()) return true;
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
// do not apply visibility and linkage constraints to code coverage
|
|
|
|
|
if(!coverage)
|
|
|
|
|
{
|
|
|
|
|
if(is_linkage_constrained()) return false;
|
|
|
|
|
if(is_visibility_constrained()) return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
if(is_address_range_constrained()) return false;
|
|
|
|
|
if(is_num_instructions_constrained()) return false;
|
2023-02-07 03:39:10 -06:00
|
|
|
if(is_instruction_constrained()) return false;
|
2022-03-07 20:40:48 -06:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_instrumentable() const
|
|
|
|
|
{
|
|
|
|
|
if(!function->isInstrumentable())
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "module", "not-instrumentable", module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
bool
|
|
|
|
|
check_regex_restrictions(const std::string& _name, const regexvec_t& _regexes)
|
|
|
|
|
{
|
|
|
|
|
// NOLINTNEXTLINE
|
|
|
|
|
for(auto& itr : _regexes)
|
|
|
|
|
if(std::regex_search(_name, itr)) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_user_restricted() const
|
|
|
|
|
{
|
|
|
|
|
if(!file_restrict.empty())
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(module_name, file_restrict))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "module", "module-restrict-regex",
|
|
|
|
|
module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(3, "Skipping", "module", "module-restrict-regex",
|
|
|
|
|
module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!func_restrict.empty())
|
|
|
|
|
{
|
2022-04-25 17:00:52 -05:00
|
|
|
if(check_regex_restrictions(function_name, func_restrict))
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "function", "function-restrict-regex",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else if(check_regex_restrictions(signature.get(), func_restrict))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "function", "function-restrict-regex",
|
|
|
|
|
signature.get());
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(3, "Skipping", "function", "function-restrict-regex",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_user_included() const
|
|
|
|
|
{
|
|
|
|
|
if(!file_include.empty())
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(module_name, file_include))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "module", "module-include-regex",
|
|
|
|
|
module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!func_include.empty())
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(function_name, func_include))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "function", "function-include-regex",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if(check_regex_restrictions(signature.get(), func_include))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "function", "function-include-regex",
|
|
|
|
|
signature.get());
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-11 09:32:57 +01:00
|
|
|
return contains_user_callsite();
|
2022-03-07 20:40:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_user_excluded() const
|
|
|
|
|
{
|
|
|
|
|
if(!file_exclude.empty())
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(module_name, file_exclude))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "module", "module-exclude-regex",
|
|
|
|
|
module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!func_exclude.empty())
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(function_name, func_exclude))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "function-exclude-regex",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if(check_regex_restrictions(signature.get(), func_exclude))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "function-exclude-regex",
|
|
|
|
|
signature.get());
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_overlapping() const
|
|
|
|
|
{
|
|
|
|
|
procedure_vec_t _overlapping{};
|
|
|
|
|
return function->findOverlapping(_overlapping);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
symbol_linkage_t
|
|
|
|
|
module_function::get_linkage() const
|
|
|
|
|
{
|
|
|
|
|
constexpr auto unknown_v = SymTab::Symbol::SL_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
if(symtab_function == nullptr) return unknown_v;
|
|
|
|
|
symbol_linkage_t _v = unknown_v;
|
|
|
|
|
for(const auto& itr : symtab_data.symbols.at(symtab_function))
|
|
|
|
|
{
|
|
|
|
|
auto litr = itr->getLinkage();
|
|
|
|
|
if(litr > unknown_v) _v = (_v == unknown_v) ? litr : std::min(_v, litr);
|
|
|
|
|
}
|
|
|
|
|
return _v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
symbol_visibility_t
|
|
|
|
|
module_function::get_visibility() const
|
|
|
|
|
{
|
|
|
|
|
constexpr auto unknown_v = SymTab::Symbol::SV_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
if(symtab_function == nullptr) return unknown_v;
|
|
|
|
|
symbol_visibility_t _v = unknown_v;
|
|
|
|
|
for(const auto& itr : symtab_data.symbols.at(symtab_function))
|
|
|
|
|
{
|
|
|
|
|
auto litr = itr->getVisibility();
|
|
|
|
|
if(litr > unknown_v) _v = (_v == unknown_v) ? litr : std::min(_v, litr);
|
|
|
|
|
}
|
|
|
|
|
return _v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_internal_constrained() const
|
|
|
|
|
{
|
|
|
|
|
using ::timemory::join::join;
|
|
|
|
|
auto _basename = [](std::string_view _v) {
|
|
|
|
|
return std::string{ tim::filepath::basename(_v) };
|
|
|
|
|
};
|
|
|
|
|
auto _realpath = [](const std::string& _v) {
|
|
|
|
|
return tim::filepath::realpath(_v, nullptr, false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto _report = [&](const string_t& _action, const std::string& _type,
|
|
|
|
|
const string_t& _reason, int _lvl) {
|
|
|
|
|
messages.emplace_back(_lvl, _action, _type, _reason, module_name);
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto& _gnu_libs = get_internal_libs_data();
|
|
|
|
|
|
|
|
|
|
auto _module_base = _basename(module_name);
|
|
|
|
|
auto _module_real = _realpath(module_name);
|
|
|
|
|
|
2024-10-15 11:20:40 -04:00
|
|
|
if(std::regex_search(module_name,
|
|
|
|
|
std::regex{ "lib(rocprof-sys|rocprofsys|timemory|perfetto)" }))
|
|
|
|
|
return _report("Excluding", "module", "rocprofsys", 3);
|
2023-02-07 03:39:10 -06:00
|
|
|
else if(std::regex_match(module_name,
|
|
|
|
|
std::regex{ ".*/source/lib/"
|
2024-10-15 11:20:40 -04:00
|
|
|
"(core|common|binary|"
|
|
|
|
|
"rocprofsys|rocprofsys-dl|"
|
|
|
|
|
"rocprofsys-user)/.*/.*\\.(h|c|cpp|hpp)$" }))
|
|
|
|
|
return _report("Excluding", "module", "rocprofsys", 3);
|
|
|
|
|
|
|
|
|
|
if(std::regex_search(function_name,
|
|
|
|
|
std::regex{ "10rocprofsys|rocprofsys|rocprofsys(::|_)" }))
|
|
|
|
|
return _report("Excluding", "function", "rocprofsys", 3);
|
2023-02-07 03:39:10 -06:00
|
|
|
else if(std::regex_search(function_name, std::regex{ "3tim|tim::|timemory(::|_)" }))
|
|
|
|
|
return _report("Excluding", "function", "timemory", 3);
|
|
|
|
|
else if(std::regex_search(function_name, std::regex{ "9perfetto|perfetto(::|_)" }))
|
|
|
|
|
return _report("Excluding", "function", "perfetto", 3);
|
|
|
|
|
|
|
|
|
|
if(_gnu_libs.find(module_name) != _gnu_libs.end() ||
|
|
|
|
|
_gnu_libs.find(_module_real) != _gnu_libs.end() ||
|
|
|
|
|
_gnu_libs.find(_module_base) != _gnu_libs.end())
|
|
|
|
|
return _report("Excluding", "module", "internal library", 3);
|
|
|
|
|
|
|
|
|
|
for(const auto& litr : _gnu_libs)
|
|
|
|
|
{
|
|
|
|
|
if(_module_base == _basename(litr.first) ||
|
|
|
|
|
litr.second.find(_module_base) != litr.second.end() ||
|
|
|
|
|
_module_real == litr.first ||
|
|
|
|
|
litr.second.find(_module_real) != litr.second.end() ||
|
|
|
|
|
litr.second.find(module_name) != litr.second.end())
|
|
|
|
|
return _report("Excluding", "module",
|
|
|
|
|
join(" ", "internal library", litr.first), 3);
|
|
|
|
|
|
|
|
|
|
for(const auto& fitr : litr.second)
|
|
|
|
|
{
|
|
|
|
|
using ::timemory::join::join;
|
|
|
|
|
if(fitr.second.find(function_name) != fitr.second.end())
|
|
|
|
|
return _report("Excluding", "function",
|
|
|
|
|
join(" ", "internal library", litr.first), 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
bool
|
|
|
|
|
module_function::is_module_constrained() const
|
|
|
|
|
{
|
2022-04-25 17:00:52 -05:00
|
|
|
auto regex_opts = std::regex_constants::egrep | std::regex_constants::optimize;
|
|
|
|
|
auto _report = [&](const string_t& _action, const string_t& _reason, int _lvl) {
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(_lvl, _action, "module", _reason, module_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
2022-04-25 17:00:52 -05:00
|
|
|
};
|
|
|
|
|
|
2022-08-08 08:37:51 -05:00
|
|
|
if(module->isSystemLib()) return _report("Excluding", "system library", 3);
|
2022-04-25 17:00:52 -05:00
|
|
|
|
|
|
|
|
// always instrument these modules
|
|
|
|
|
if(module_name == "DEFAULT_MODULE" || module_name == "LIBRARY_MODULE")
|
2023-03-14 19:48:29 -05:00
|
|
|
// return _report("Skipping", "default module", 2);
|
|
|
|
|
return false;
|
2022-04-25 17:00:52 -05:00
|
|
|
|
|
|
|
|
static std::regex ext_regex{ "\\.(s|S)$", regex_opts };
|
|
|
|
|
static std::regex sys_regex{ "^(s|k|e|w)_[A-Za-z_0-9\\-]+\\.(c|C)$", regex_opts };
|
|
|
|
|
static std::regex sys_build_regex{ "^(\\.\\./sysdeps/|/build/)", regex_opts };
|
|
|
|
|
static std::regex dyninst_regex{ "(dyninst|DYNINST|(^|/)RT[[:graph:]]+\\.c$)",
|
|
|
|
|
regex_opts };
|
2024-10-15 11:20:40 -04:00
|
|
|
static std::regex dependlib_regex{ "^(lib|)(rocprof-sys|rocprofsys|"
|
|
|
|
|
"pthread|caliper|gotcha|papi|"
|
2022-04-25 17:00:52 -05:00
|
|
|
"cupti|TAU|likwid|pfm|nvperf|unwind)",
|
|
|
|
|
regex_opts };
|
|
|
|
|
static std::regex core_cmod_regex{
|
|
|
|
|
"^(malloc|(f|)lock|sig|sem)[a-z_]+(|64|_r|_l)\\.c$"
|
|
|
|
|
};
|
2023-02-07 03:39:10 -06:00
|
|
|
static std::regex core_lib_regex{ "lib(elf)(-|\\.)", regex_opts };
|
|
|
|
|
// static std::regex prefix_regex{ "^(_|\\.[a-zA-Z0-9])", regex_opts };
|
2022-04-25 17:00:52 -05:00
|
|
|
|
|
|
|
|
// file extensions that should not be instrumented
|
|
|
|
|
if(std::regex_search(module_name, ext_regex))
|
|
|
|
|
return _report("Excluding", "file extension", 3);
|
|
|
|
|
|
|
|
|
|
// system modules that should not be instrumented (wastes time)
|
|
|
|
|
if(std::regex_search(module_name, sys_regex) ||
|
|
|
|
|
std::regex_search(module_name, sys_build_regex))
|
|
|
|
|
return _report("Excluding", "system module", 3);
|
|
|
|
|
|
|
|
|
|
// dyninst modules that must not be instrumented
|
|
|
|
|
if(std::regex_search(module_name, dyninst_regex))
|
|
|
|
|
return _report("Excluding", "dyninst module", 3);
|
|
|
|
|
|
2024-10-15 11:20:40 -04:00
|
|
|
// modules used by rocprof-sys and dependent libraries
|
2022-04-25 17:00:52 -05:00
|
|
|
if(std::regex_search(module_name, core_lib_regex) ||
|
|
|
|
|
std::regex_search(module_name, core_cmod_regex))
|
|
|
|
|
return _report("Excluding", "core module", 3);
|
|
|
|
|
|
2024-10-15 11:20:40 -04:00
|
|
|
// modules used by rocprof-sys and dependent libraries
|
2022-04-25 17:00:52 -05:00
|
|
|
if(std::regex_search(module_name, dependlib_regex))
|
|
|
|
|
return _report("Excluding", "dependency module", 3);
|
|
|
|
|
|
|
|
|
|
// known set of modules whose starting sequence of characters suggest it should not be
|
|
|
|
|
// instrumented (wastes time)
|
2023-02-07 03:39:10 -06:00
|
|
|
// if(std::regex_search(module_name, prefix_regex))
|
|
|
|
|
// return _report("Excluding", "prefix match", 3);
|
2022-04-25 17:00:52 -05:00
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_routine_constrained() const
|
|
|
|
|
{
|
2022-04-25 17:00:52 -05:00
|
|
|
auto regex_opts = std::regex_constants::egrep | std::regex_constants::optimize;
|
|
|
|
|
auto _report = [&](const string_t& _action, const string_t& _reason, int _lvl) {
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(_lvl, _action, "function", _reason, function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
2022-04-25 17:00:52 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto npos = std::string::npos;
|
2024-10-15 11:20:40 -04:00
|
|
|
if(function_name.find("rocprofsys") != npos)
|
2022-04-25 17:00:52 -05:00
|
|
|
{
|
2024-10-15 11:20:40 -04:00
|
|
|
return _report("Skipping", "rocprofsys-function", 1);
|
2022-03-07 20:40:48 -06:00
|
|
|
}
|
2022-04-25 17:00:52 -05:00
|
|
|
|
|
|
|
|
if(function_name.find("FunctionInfo") != npos ||
|
|
|
|
|
function_name.find("_L_lock") != npos || function_name.find("_L_unlock") != npos)
|
|
|
|
|
{
|
|
|
|
|
return _report("Skipping", "function-constraint", 2);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 11:20:40 -04:00
|
|
|
static std::regex exclude("(rocprofsys|rocprof-sys|tim::|MPI_Init|MPI_"
|
|
|
|
|
"Finalize|dyninst|DYNINST|tm_clones)",
|
|
|
|
|
regex_opts);
|
2023-02-07 03:39:10 -06:00
|
|
|
// static std::regex exclude_printf("(|v|f)printf$", regex_opts);
|
2022-04-25 17:00:52 -05:00
|
|
|
static std::regex exclude_cxx(
|
|
|
|
|
"(std::_Sp_counted_base|std::(use|has)_facet|std::locale|::sentry|^std::_|::_(M|"
|
|
|
|
|
"S)_|::basic_string[a-zA-Z,<>: ]+::_M_create|::__|::_(Alloc|State)|"
|
|
|
|
|
"std::(basic_|)(ifstream|ios|istream|ostream|stream))",
|
|
|
|
|
regex_opts);
|
2022-05-24 19:26:12 -05:00
|
|
|
static std::regex leading(
|
2023-02-07 03:39:10 -06:00
|
|
|
"^(\\.|frame_dummy|transaction clone|virtual thunk|non-virtual thunk|"
|
|
|
|
|
"\\(|targ|kmp_threadprivate_|Kokkos::Profiling::|_IO_|___|"
|
|
|
|
|
"__(GI|cxa|libc|IO|rpc|run|call|pthread|dl|nl|nss|new|old|internal|argp|malloc|"
|
|
|
|
|
"libio|printf)_)",
|
2022-05-24 19:26:12 -05:00
|
|
|
regex_opts);
|
2023-02-07 03:39:10 -06:00
|
|
|
static std::regex trailing("(_internal)$", regex_opts);
|
|
|
|
|
// static std::regex trailing(
|
|
|
|
|
// "(_|\\.part\\.[0-9]+|\\.constprop\\.[0-9]+|\\.|\\.[0-9]+)$", regex_opts);
|
2022-04-25 17:00:52 -05:00
|
|
|
static strset_t whole = []() {
|
|
|
|
|
auto _v = get_whole_function_names();
|
|
|
|
|
auto _ret = _v;
|
|
|
|
|
for(std::string _ext : { "64", "_l", "_r" })
|
|
|
|
|
for(const auto& itr : _v)
|
|
|
|
|
_ret.emplace(itr + _ext);
|
|
|
|
|
return _ret;
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
// don't instrument the functions when key is found anywhere in function name
|
|
|
|
|
if(std::regex_search(function_name, exclude) ||
|
|
|
|
|
std::regex_search(function_name, exclude_cxx))
|
|
|
|
|
{
|
|
|
|
|
return _report("Excluding", "critical", 3);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
// if(std::regex_search(function_name, exclude_printf))
|
|
|
|
|
//{
|
|
|
|
|
// return _report("Excluding", "critical-printf", 3);
|
|
|
|
|
//}
|
2022-07-25 12:16:11 -05:00
|
|
|
|
2022-04-25 17:00:52 -05:00
|
|
|
if(whole.count(function_name) > 0)
|
|
|
|
|
{
|
|
|
|
|
return _report("Excluding", "critical-whole-match", 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't instrument the functions when key is found at the start of the function name
|
|
|
|
|
if(std::regex_search(function_name, leading))
|
|
|
|
|
{
|
|
|
|
|
return _report("Excluding", "recommended-leading-match", 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't instrument the functions when key is found at the end of the function name
|
|
|
|
|
if(std::regex_search(function_name, trailing))
|
|
|
|
|
{
|
|
|
|
|
return _report("Excluding", "recommended-trailing-match", 3);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_overlapping_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(!allow_overlapping && is_overlapping())
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "overlapping", function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::contains_dynamic_callsites() const
|
|
|
|
|
{
|
|
|
|
|
if(flow_graph) return flow_graph->containsDynamicCallsites();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-11 09:32:57 +01:00
|
|
|
bool
|
|
|
|
|
module_function::contains_user_callsite() const
|
|
|
|
|
{
|
|
|
|
|
if(caller_include.empty()) return false;
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
std::vector<BPatch_point*> call_points;
|
2022-11-11 09:32:57 +01:00
|
|
|
function->getCallPoints(call_points);
|
|
|
|
|
for(const auto& call_point : call_points)
|
|
|
|
|
{
|
|
|
|
|
if(check_regex_restrictions(
|
|
|
|
|
std::string(get_name(call_point->getCalledFunction())), caller_include))
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(2, "Forcing", "function", "caller-include-regex",
|
|
|
|
|
function_name);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
bool
|
|
|
|
|
module_function::is_dynamic_callsite_forced() const
|
|
|
|
|
{
|
|
|
|
|
if(instr_dynamic_callsites && contains_dynamic_callsites())
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Forcing", "function", "dynamic-callsites",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_address_range_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(!loop_blocks.empty()) return is_loop_address_range_constrained();
|
|
|
|
|
|
|
|
|
|
if(address_range < min_address_range)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "min-address-range",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
bool
|
|
|
|
|
module_function::is_instruction_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(!instruction_exclude.empty())
|
|
|
|
|
{
|
|
|
|
|
for(auto&& itr : instructions)
|
|
|
|
|
{
|
|
|
|
|
auto _instrss = std::stringstream{};
|
|
|
|
|
for(auto&& iitr : itr)
|
|
|
|
|
_instrss << " " << iitr.first.format();
|
|
|
|
|
|
|
|
|
|
auto _instr = _instrss.str();
|
|
|
|
|
if(!_instr.empty())
|
|
|
|
|
{
|
|
|
|
|
_instr = _instr.substr(1);
|
|
|
|
|
if(check_regex_restrictions(_instr, instruction_exclude))
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(2, "Skipping", "function",
|
|
|
|
|
"instruction-exclude-regex", function_name);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
bool
|
|
|
|
|
module_function::is_loop_address_range_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(loop_blocks.empty()) return false;
|
|
|
|
|
|
|
|
|
|
if(address_range < min_loop_address_range)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "min-address-range-loop",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_num_instructions_constrained() const
|
|
|
|
|
{
|
2022-04-25 17:00:52 -05:00
|
|
|
if(!loop_blocks.empty()) return is_loop_num_instructions_constrained();
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
if(num_instructions < min_instructions)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "min-instructions",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 17:00:52 -05:00
|
|
|
bool
|
|
|
|
|
module_function::is_loop_num_instructions_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(loop_blocks.empty()) return false;
|
|
|
|
|
|
|
|
|
|
if(num_instructions < min_loop_instructions)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(2, "Skipping", "function", "min-instructions-loop",
|
|
|
|
|
function_name);
|
2022-04-25 17:00:52 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
bool
|
|
|
|
|
module_function::is_visibility_constrained() const
|
|
|
|
|
{
|
|
|
|
|
auto _visibility = get_visibility();
|
|
|
|
|
return (_visibility != SV_UNKNOWN &&
|
|
|
|
|
enabled_visibility.find(_visibility) == enabled_visibility.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_linkage_constrained() const
|
|
|
|
|
{
|
|
|
|
|
auto _linkage = get_linkage();
|
|
|
|
|
return (_linkage != SL_UNKNOWN &&
|
|
|
|
|
enabled_linkage.find(_linkage) == enabled_linkage.end());
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
bool
|
|
|
|
|
module_function::can_instrument_entry() const
|
|
|
|
|
{
|
|
|
|
|
size_t _num_points = 0;
|
|
|
|
|
size_t _num_traps = 0;
|
|
|
|
|
|
|
|
|
|
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_entry);
|
|
|
|
|
|
|
|
|
|
if(_num_points == 0)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(3, "Skipping", "function", "no-instrumentable-entry-point",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::can_instrument_exit() const
|
|
|
|
|
{
|
|
|
|
|
size_t _num_points = 0;
|
|
|
|
|
size_t _num_traps = 0;
|
|
|
|
|
|
|
|
|
|
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_exit);
|
|
|
|
|
|
|
|
|
|
if(_num_points == 0)
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(3, "Skipping", "function", "no-instrumentable-exit-point",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_entry_trap_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(instr_traps) return false;
|
|
|
|
|
|
|
|
|
|
size_t _num_points = 0;
|
|
|
|
|
size_t _num_traps = 0;
|
|
|
|
|
|
|
|
|
|
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_entry);
|
|
|
|
|
|
|
|
|
|
if(!instr_traps && (_num_points - _num_traps) == 0)
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(3, "Skipping", "function",
|
2022-06-10 06:57:50 -05:00
|
|
|
"entry-point-trap-instrumentation", function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
module_function::is_exit_trap_constrained() const
|
|
|
|
|
{
|
|
|
|
|
if(instr_traps) return false;
|
|
|
|
|
|
|
|
|
|
size_t _num_points = 0;
|
|
|
|
|
size_t _num_traps = 0;
|
|
|
|
|
|
|
|
|
|
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_exit);
|
|
|
|
|
|
|
|
|
|
if((_num_points - _num_traps) == 0)
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(3, "Skipping", "function",
|
2022-06-10 06:57:50 -05:00
|
|
|
"exit-point-trap-instrumentation", function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<size_t, size_t>
|
|
|
|
|
module_function::operator()(address_space_t* _addr_space, procedure_t* _entr_trace,
|
|
|
|
|
procedure_t* _exit_trace) const
|
|
|
|
|
{
|
|
|
|
|
std::pair<size_t, size_t> _count = { 0, 0 };
|
|
|
|
|
|
2023-02-07 03:39:10 -06:00
|
|
|
if(!function || !module) return _count;
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
auto _name = signature.get();
|
2024-10-15 11:20:40 -04:00
|
|
|
auto _trace_entr = rocprofsys_call_expr(_name.c_str());
|
|
|
|
|
auto _trace_exit = rocprofsys_call_expr(_name.c_str());
|
2022-03-07 20:40:48 -06:00
|
|
|
auto _entr = _trace_entr.get(_entr_trace);
|
|
|
|
|
auto _exit = _trace_exit.get(_exit_trace);
|
|
|
|
|
|
2022-04-25 17:00:52 -05:00
|
|
|
if(insert_instr(_addr_space, function, _entr, BPatch_entry) &&
|
|
|
|
|
insert_instr(_addr_space, function, _exit, BPatch_exit))
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(1, "Instrumenting", "function", "no-constraint",
|
|
|
|
|
function_name);
|
2022-03-07 20:40:48 -06:00
|
|
|
++_count.first;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
for(size_t i = 0; i < loop_blocks.size(); ++i)
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
|
|
|
|
if(!loop_level_instr) continue;
|
2023-02-07 03:39:10 -06:00
|
|
|
if(!flow_graph) continue;
|
2022-03-07 20:40:48 -06:00
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
auto* itr = loop_blocks.at(i);
|
|
|
|
|
auto _is_constrained = [this](bool _v, const std::string& _label,
|
2022-09-28 14:28:32 -05:00
|
|
|
const std::string& _mname) {
|
2022-06-10 06:57:50 -05:00
|
|
|
if(_v)
|
2022-03-07 20:40:48 -06:00
|
|
|
{
|
2022-09-28 14:28:32 -05:00
|
|
|
messages.emplace_back(3, "Skipping", "function-loop", _label, _mname);
|
2022-03-07 20:40:48 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
auto lname =
|
|
|
|
|
get_loop_file_line_info(module, function, flow_graph, itr).set_loop_number(i);
|
|
|
|
|
auto _lname = lname.get();
|
|
|
|
|
|
2022-03-07 20:40:48 -06:00
|
|
|
size_t _points = 0;
|
|
|
|
|
size_t _ntraps = 0;
|
|
|
|
|
std::tie(_points, _ntraps) = query_instr(function, BPatch_entry, flow_graph, itr);
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
if(_is_constrained(_points == 0, "no-instrumentable-loop-entry-point", _lname))
|
|
|
|
|
continue;
|
|
|
|
|
if(_is_constrained(!instr_loop_traps && _points == _ntraps,
|
|
|
|
|
"loop-entry-point-trap-instrumentation", _lname))
|
2022-03-07 20:40:48 -06:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
std::tie(_points, _ntraps) = query_instr(function, BPatch_exit, flow_graph, itr);
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
if(_is_constrained(_points == 0, "no-instrumentable-loop-exit-point", _lname))
|
|
|
|
|
continue;
|
|
|
|
|
if(_is_constrained(!instr_loop_traps && _points == _ntraps,
|
|
|
|
|
"loop-exit-point-trap-instrumentation", _lname))
|
2022-03-07 20:40:48 -06:00
|
|
|
continue;
|
|
|
|
|
|
2024-10-15 11:20:40 -04:00
|
|
|
auto _ltrace_entr = rocprofsys_call_expr(_lname.c_str());
|
|
|
|
|
auto _ltrace_exit = rocprofsys_call_expr(_lname.c_str());
|
2022-03-07 20:40:48 -06:00
|
|
|
auto _lentr = _ltrace_entr.get(_entr_trace);
|
|
|
|
|
auto _lexit = _ltrace_exit.get(_exit_trace);
|
|
|
|
|
|
2022-06-10 06:57:50 -05:00
|
|
|
if(insert_instr(_addr_space, function, _lentr, BPatch_entry, flow_graph, itr,
|
|
|
|
|
instr_loop_traps) &&
|
|
|
|
|
insert_instr(_addr_space, function, _lexit, BPatch_exit, flow_graph, itr,
|
|
|
|
|
instr_loop_traps))
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(1, "Loop Instrumenting", "function", "no-constraint",
|
|
|
|
|
_lname);
|
|
|
|
|
++_count.second;
|
|
|
|
|
}
|
2022-03-07 20:40:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _count;
|
|
|
|
|
}
|
2022-04-25 17:00:52 -05:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
module_function::register_source(address_space_t* _addr_space, procedure_t* _entr_trace,
|
|
|
|
|
const std::vector<point_t*>& _entr_points) const
|
|
|
|
|
{
|
|
|
|
|
switch(coverage_mode)
|
|
|
|
|
{
|
|
|
|
|
case CODECOV_FUNCTION:
|
|
|
|
|
{
|
|
|
|
|
auto _name = signature.get_coverage(false);
|
|
|
|
|
auto _trace_entr =
|
2024-10-15 11:20:40 -04:00
|
|
|
rocprofsys_call_expr(signature.m_file, signature.m_name,
|
|
|
|
|
signature.m_row.first, start_address, _name);
|
2022-04-25 17:00:52 -05:00
|
|
|
auto _entr = _trace_entr.get(_entr_trace);
|
|
|
|
|
|
|
|
|
|
if(insert_instr(_addr_space, _entr_points, _entr, BPatch_entry))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(1, "Code Coverage", "function", "no-constraint",
|
|
|
|
|
_name);
|
2022-04-25 17:00:52 -05:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODECOV_BASIC_BLOCK:
|
|
|
|
|
{
|
|
|
|
|
for(auto&& itr : get_basic_block_file_line_info(module, function))
|
|
|
|
|
{
|
|
|
|
|
auto _start_addr = itr.second.start_address;
|
|
|
|
|
auto& _signature = itr.second.signature;
|
|
|
|
|
auto _name = _signature.get_coverage(true);
|
|
|
|
|
auto _trace_entr =
|
2024-10-15 11:20:40 -04:00
|
|
|
rocprofsys_call_expr(_signature.m_file, _signature.m_name,
|
|
|
|
|
_signature.m_row.first, _start_addr, _name);
|
2022-04-25 17:00:52 -05:00
|
|
|
auto _entr = _trace_entr.get(_entr_trace);
|
|
|
|
|
|
|
|
|
|
if(insert_instr(_addr_space, _entr_points, _entr, BPatch_entry))
|
|
|
|
|
{
|
|
|
|
|
messages.emplace_back(1, "Code Coverage", "basic_block",
|
2022-06-10 06:57:50 -05:00
|
|
|
"no-constraint", _name);
|
2022-04-25 17:00:52 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODECOV_NONE: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<size_t, size_t>
|
|
|
|
|
module_function::register_coverage(address_space_t* _addr_space,
|
|
|
|
|
procedure_t* _entr_trace) const
|
|
|
|
|
{
|
|
|
|
|
std::pair<size_t, size_t> _count = { 0, 0 };
|
|
|
|
|
switch(coverage_mode)
|
|
|
|
|
{
|
|
|
|
|
case CODECOV_FUNCTION:
|
|
|
|
|
{
|
|
|
|
|
auto _trace_entr =
|
2024-10-15 11:20:40 -04:00
|
|
|
rocprofsys_call_expr(signature.m_file, signature.m_name, start_address);
|
2022-04-25 17:00:52 -05:00
|
|
|
auto _entr = _trace_entr.get(_entr_trace);
|
|
|
|
|
|
|
|
|
|
if(insert_instr(_addr_space, function, _entr, BPatch_entry))
|
|
|
|
|
{
|
2022-06-10 06:57:50 -05:00
|
|
|
messages.emplace_back(1, "Code Coverage", "function", "no-constraint",
|
|
|
|
|
signature.get_coverage(false));
|
2022-04-25 17:00:52 -05:00
|
|
|
++_count.first;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODECOV_BASIC_BLOCK:
|
|
|
|
|
{
|
|
|
|
|
for(auto&& itr : get_basic_block_file_line_info(module, function))
|
|
|
|
|
{
|
|
|
|
|
auto _start_addr = itr.second.start_address;
|
|
|
|
|
auto& _signature = itr.second.signature;
|
2024-10-15 11:20:40 -04:00
|
|
|
auto _trace_entr = rocprofsys_call_expr(_signature.m_file,
|
|
|
|
|
_signature.m_name, _start_addr);
|
2022-04-25 17:00:52 -05:00
|
|
|
auto _entr = _trace_entr.get(_entr_trace);
|
|
|
|
|
|
|
|
|
|
if(insert_instr(_addr_space, _entr, BPatch_entry, itr.first))
|
|
|
|
|
{
|
|
|
|
|
++_count.second;
|
|
|
|
|
messages.emplace_back(1, "Code Coverage", "basic_block",
|
2022-06-10 06:57:50 -05:00
|
|
|
"no-constraint", _signature.get_coverage(true));
|
2022-04-25 17:00:52 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODECOV_NONE: break;
|
|
|
|
|
}
|
|
|
|
|
return _count;
|
|
|
|
|
}
|