rocprofv3: summary reports + more JSON metadata (#1029)
* Move include/rocprofiler-sdk/cxx/details/delimit.hpp to tokenize.hpp
* Update docs/how-to/using-rocprofv3.rst
- fix code block indents
- reorder rocprofv3 options, limit them to important options
- add docs for `--runtime-trace`
* Update rocprofv3.py
- parser argument groups
- new `--runtime-trace` option
- new `--summary` option
- new `--summary-per-domain` option
- new `--summary-groups` option
- new `--summary-output-file` option
- new `--summary-units` option
* Update lib/rocprofiler-sdk/hsa/async_copy.cpp
- fix async copy operation names: add "MEMORY_COPY_" prefix
* lib/rocprofiler-sdk-tool: update statistics.{hpp,cpp}
- statistics<>::get_percent function
- stats_entry_t struct
- stats_formatter struct
- percentage struct
- std::to_string(::rocprofiler::tool::percentage)
* lib/rocprofiler-sdk-tool: update domain_type.{hpp,cpp}
- reorder domain_type enum values
* lib/rocprofiler-sdk-tool: update generateCSV.{hpp,cpp}
- separate writing CSV from accumulating statistics
- a lot of functionality was moved to statistics.{hpp,cpp}
* lib/rocprofiler-sdk-tool: update output_file.{hpp,cpp}
- output_stream_t struct
- get_output_stream(...) returns output_stream_t instance
* lib/rocprofiler-sdk-tool: update generateJSON.cpp
- update get_output_stream usage to output_stream_t
* lib/rocprofiler-sdk-tool: update generateOTF2.cpp
- header include order tweak
* lib/rocprofiler-sdk-tool: update buffered_output.hpp
- stats_data_t was renamed to stats_entry_t
* lib/rocprofiler-sdk-tool: update generatePerfetto.cpp
- header include tweak
* lib/rocprofiler-sdk-tool: update tmp_file_buffer.hpp
- emit warning message if write_ring_buffer fails after offloading instead of aborting
- prefer placement new instead of assignment in write_ring_buffer
* lib/rocprofiler-sdk-tool: add generateStats.{hpp,cpp}
- functions for accumulating statistics
* Update tests/rocprofv3/tracing-hip-in-libraries/CMakeLists.txt
- accommodate tweak to CSV output file name for HIP and HSA traces
* lib/rocprofiler-sdk-tool: update config.{hpp,cpp}
- new config variables
- stats_summary
- stats_summary_per_domain
- summary_output
- stats_summary_unit_value
- stats_summary_unit
- stats_summary_file
- stats_summary_groups
- support output keys for hostname: %hostname% / %h
* lib/rocprofiler-sdk-tool: update tool.cpp
- support summary output
* Documentation fixes
* Test for summary output
* Update tests/bin/transpose to use more ROCTx
- also support building with the roctracer ROCTx
* Remove roctxMark from OTF2 + fix kernel-rename tests
- following more ROCTx calls in transpose, kernel-rename validation had to be updated
* JSON metadata + JSON summary
- add serialization support for config
- add serialization support for statistics
- additions to json spec
- rocprofiler-sdk-tool/metadata/config
- rocprofiler-sdk-tool/metadata/command
- rocprofiler-sdk-tool/summary
- config output_keys support for NVIDIA %q{<ENV-VAR>} syntax
- config output_keys support keys within keys
* rocprofv3 --summary-groups warning if no domain matches
- emit warning if a regex in for summary groups did not match any domain names
* Compile fix for lib/rocprofiler-sdk-tool/tool.cpp
- get_config().scratch_memory_trace
- pass contributions to write_json
* Update rocprofv3.py to preload rocprofiler-sdk-roctx
- appended to LD_PRELOAD when args.marker_trace is enabled
* Fix ReST link errors about subtitle underline being too short
* Patch tokenization of config::stats_summary_groups
- guard against array values of empty strings
* Tweak rocprofv3 summary test
- input-summary.yaml (used by rocprofv3-test-summary-inp-yaml-execute) only provides one summary group regex
* Disable LD_PRELOAD of librocprofiler-sdk-roctx.so
- this causes problems in the sanitizers, will be addressed in another PR
Tento commit je obsažen v:
@@ -13,6 +13,7 @@ set(TOOL_HEADERS
|
||||
generateJSON.hpp
|
||||
generateOTF2.hpp
|
||||
generatePerfetto.hpp
|
||||
generateStats.hpp
|
||||
helper.hpp
|
||||
output_file.hpp
|
||||
statistics.hpp
|
||||
@@ -26,9 +27,11 @@ set(TOOL_SOURCES
|
||||
generateJSON.cpp
|
||||
generateOTF2.cpp
|
||||
generatePerfetto.cpp
|
||||
generateStats.cpp
|
||||
helper.cpp
|
||||
main.c
|
||||
output_file.cpp
|
||||
statistics.cpp
|
||||
tmp_file_buffer.cpp
|
||||
tmp_file.cpp
|
||||
tool.cpp)
|
||||
|
||||
@@ -59,7 +59,7 @@ struct buffered_output
|
||||
operator bool() const { return enabled; }
|
||||
|
||||
std::deque<Tp> element_data = {};
|
||||
stats_data_t stats = {};
|
||||
stats_entry_t stats = {};
|
||||
|
||||
private:
|
||||
bool enabled = false;
|
||||
|
||||
@@ -28,12 +28,14 @@
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/logging.hpp"
|
||||
#include "lib/common/units.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/cxx/details/delimit.hpp>
|
||||
#include <rocprofiler-sdk/cxx/details/tokenize.hpp>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
@@ -44,6 +46,7 @@
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
@@ -67,8 +70,14 @@ const auto* launch_clock = as_pointer(std::chrono::system_clock::now());
|
||||
const auto* launch_datetime =
|
||||
get_local_datetime(get_env("ROCP_TIME_FORMAT", "%F_%H.%M"), launch_time);
|
||||
const auto env_regexes =
|
||||
new std::array<std::regex, 2>{std::regex{"(.*)%(env|ENV)\\{([A-Z0-9_]+)\\}%(.*)"},
|
||||
std::regex{"(.*)\\$(env|ENV)\\{([A-Z0-9_]+)\\}(.*)"}};
|
||||
new std::array<std::regex, 3>{std::regex{"(.*)%(env|ENV)\\{([A-Z0-9_]+)\\}%(.*)"},
|
||||
std::regex{"(.*)\\$(env|ENV)\\{([A-Z0-9_]+)\\}(.*)"},
|
||||
std::regex{"(.*)%q\\{([A-Z0-9_]+)\\}(.*)"}};
|
||||
// env regex examples:
|
||||
// - %env{USER}% Consistent with other output key formats (start+end with %)
|
||||
// - $ENV{USER} Similar to CMake
|
||||
// - %q{USER} Compatibility with NVIDIA
|
||||
//
|
||||
|
||||
std::string*
|
||||
get_local_datetime(const std::string& dt_format, std::time_t*& _dt_curr)
|
||||
@@ -86,6 +95,22 @@ get_local_datetime(const std::string& dt_format, std::time_t*& _dt_curr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string
|
||||
get_hostname()
|
||||
{
|
||||
auto _hostname_buff = std::array<char, PATH_MAX>{};
|
||||
_hostname_buff.fill('\0');
|
||||
if(gethostname(_hostname_buff.data(), _hostname_buff.size() - 1) != 0)
|
||||
{
|
||||
auto _err = errno;
|
||||
ROCP_WARNING << "Hostname unknown. gethostname failed with error code " << _err << ": "
|
||||
<< strerror(_err);
|
||||
return std::string{"UNKNOWN_HOSTNAME"};
|
||||
}
|
||||
|
||||
return std::string{_hostname_buff.data()};
|
||||
}
|
||||
|
||||
inline bool
|
||||
not_is_space(int ch)
|
||||
{
|
||||
@@ -279,6 +304,34 @@ config::config()
|
||||
const auto supported_perfetto_backends = std::set<std::string_view>{"inprocess", "system"};
|
||||
LOG_IF(FATAL, supported_perfetto_backends.count(perfetto_backend) == 0)
|
||||
<< "Unsupported perfetto backend type: " << perfetto_backend;
|
||||
|
||||
if(stats_summary_unit == "sec")
|
||||
stats_summary_unit_value = common::units::sec;
|
||||
else if(stats_summary_unit == "msec")
|
||||
stats_summary_unit_value = common::units::msec;
|
||||
else if(stats_summary_unit == "usec")
|
||||
stats_summary_unit_value = common::units::usec;
|
||||
else if(stats_summary_unit == "nsec")
|
||||
stats_summary_unit_value = common::units::nsec;
|
||||
else
|
||||
{
|
||||
ROCP_FATAL << "Unsupported summary units value: " << stats_summary_unit;
|
||||
}
|
||||
|
||||
if(auto _summary_grps = get_env("ROCPROF_STATS_SUMMARY_GROUPS", ""); !_summary_grps.empty())
|
||||
{
|
||||
stats_summary_groups =
|
||||
sdk::parse::tokenize(_summary_grps, std::vector<std::string_view>{"##@@##"});
|
||||
|
||||
// remove any empty strings (just in case these slipped through)
|
||||
stats_summary_groups.erase(std::remove_if(stats_summary_groups.begin(),
|
||||
stats_summary_groups.end(),
|
||||
[](const auto& itr) { return itr.empty(); }),
|
||||
stats_summary_groups.end());
|
||||
}
|
||||
|
||||
// enable summary output if any of these are enabled
|
||||
summary_output = (stats_summary || stats_summary_per_domain || !stats_summary_groups.empty());
|
||||
}
|
||||
|
||||
std::vector<output_key>
|
||||
@@ -374,8 +427,10 @@ output_keys(std::string _tag)
|
||||
}
|
||||
|
||||
auto _launch_time = (launch_datetime) ? *launch_datetime : std::string{".UNKNOWN_LAUNCH_TIME."};
|
||||
auto _hostname = get_hostname();
|
||||
|
||||
for(auto&& itr : std::initializer_list<output_key>{
|
||||
{"%hostname%", _hostname, "Network hostname"},
|
||||
{"%pid%", _proc_id, "Process identifier"},
|
||||
{"%ppid%", _parent_id, "Parent process identifier"},
|
||||
{"%pgid%", _pgroup_id, "Process group identifier"},
|
||||
@@ -392,6 +447,7 @@ output_keys(std::string _tag)
|
||||
}
|
||||
|
||||
for(auto&& itr : std::initializer_list<output_key>{
|
||||
{"%h", _hostname, "Shorthand for %hostname%"},
|
||||
{"%p", _proc_id, "Shorthand for %pid%"},
|
||||
{"%j", _slurm_job_id, "Shorthand for %job%"},
|
||||
{"%r", _slurm_proc_id, "Shorthand for %rank%"},
|
||||
@@ -404,8 +460,10 @@ output_keys(std::string _tag)
|
||||
return _options;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag)
|
||||
format_impl(std::string _fpath, const std::vector<output_key>& _keys)
|
||||
{
|
||||
if(_fpath.find('%') == std::string::npos && _fpath.find('$') == std::string::npos)
|
||||
return _fpath;
|
||||
@@ -416,20 +474,36 @@ format(std::string _fpath, const std::string& _tag)
|
||||
_v.replace(pos, pitr.key.length(), pitr.value);
|
||||
};
|
||||
|
||||
for(auto&& itr : output_keys(_tag))
|
||||
for(auto&& itr : _keys)
|
||||
_replace(_fpath, itr);
|
||||
|
||||
// environment and configuration variables
|
||||
try
|
||||
{
|
||||
auto strip_leading_and_replace =
|
||||
[](std::string_view inp_v, std::initializer_list<char> keys, const char* val) {
|
||||
auto inp = std::string{inp_v};
|
||||
for(auto key : keys)
|
||||
{
|
||||
auto pos = std::string::npos;
|
||||
while((pos = inp.find(key)) == 0)
|
||||
inp = inp.substr(pos + 1);
|
||||
|
||||
while((pos = inp.find(key)) != std::string::npos)
|
||||
inp = inp.replace(pos, 1, val);
|
||||
}
|
||||
return inp;
|
||||
};
|
||||
|
||||
for(const auto& _re : *env_regexes)
|
||||
{
|
||||
while(std::regex_search(_fpath, _re))
|
||||
{
|
||||
auto _var = std::regex_replace(_fpath, _re, "$3");
|
||||
std::string _val = get_env<std::string>(_var, "");
|
||||
auto _beg = std::regex_replace(_fpath, _re, "$1");
|
||||
auto _end = std::regex_replace(_fpath, _re, "$4");
|
||||
_val = strip_leading_and_replace(_val, {'\t', ' ', '/'}, "_");
|
||||
auto _beg = std::regex_replace(_fpath, _re, "$1");
|
||||
auto _end = std::regex_replace(_fpath, _re, "$4");
|
||||
_fpath = fmt::format("{}{}{}", _beg, _val, _end);
|
||||
}
|
||||
}
|
||||
@@ -454,6 +528,25 @@ format(std::string _fpath, const std::string& _tag)
|
||||
return _fpath;
|
||||
}
|
||||
|
||||
std::string
|
||||
format(std::string _fpath, const std::vector<output_key>& _keys)
|
||||
{
|
||||
if(_fpath.find('%') == std::string::npos && _fpath.find('$') == std::string::npos)
|
||||
return _fpath;
|
||||
|
||||
auto _ref = _fpath;
|
||||
_fpath = format_impl(std::move(_fpath), _keys);
|
||||
|
||||
return (_fpath == _ref) ? _fpath : format(std::move(_fpath), _keys);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag)
|
||||
{
|
||||
return format(std::move(_fpath), output_keys(_tag));
|
||||
}
|
||||
|
||||
std::string
|
||||
format_name(std::string_view _name, const config& _cfg)
|
||||
{
|
||||
|
||||
@@ -25,8 +25,14 @@
|
||||
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/mpl.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/cxx/serialization.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
@@ -38,6 +44,8 @@ namespace tool
|
||||
namespace fs = common::filesystem;
|
||||
using common::get_env;
|
||||
|
||||
struct config;
|
||||
|
||||
enum class config_context
|
||||
{
|
||||
global = 0,
|
||||
@@ -48,6 +56,19 @@ enum class config_context
|
||||
perfetto_plugin,
|
||||
};
|
||||
|
||||
void
|
||||
initialize();
|
||||
|
||||
template <config_context ContextT = config_context::global>
|
||||
config&
|
||||
get_config();
|
||||
|
||||
std::string
|
||||
format_name(std::string_view _name, const config& = get_config<>());
|
||||
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag = {});
|
||||
|
||||
int
|
||||
get_mpi_size();
|
||||
|
||||
@@ -67,25 +88,32 @@ struct config
|
||||
bool hsa_finalizer_ext_api_trace = get_env("ROCPROF_HSA_FINALIZER_EXT_API_TRACE", false);
|
||||
bool marker_api_trace = get_env("ROCPROF_MARKER_API_TRACE", false);
|
||||
bool memory_copy_trace = get_env("ROCPROF_MEMORY_COPY_TRACE", false);
|
||||
bool scratch_memory = get_env("ROCPROF_SCRATCH_MEMORY_TRACE", false);
|
||||
bool scratch_memory_trace = get_env("ROCPROF_SCRATCH_MEMORY_TRACE", false);
|
||||
bool counter_collection = get_env("ROCPROF_COUNTER_COLLECTION", false);
|
||||
bool hip_runtime_api_trace = get_env("ROCPROF_HIP_RUNTIME_API_TRACE", false);
|
||||
bool hip_compiler_api_trace = get_env("ROCPROF_HIP_COMPILER_API_TRACE", false);
|
||||
bool list_metrics = get_env("ROCPROF_LIST_METRICS", false);
|
||||
bool list_metrics_output_file = get_env("ROCPROF_OUTPUT_LIST_METRICS_FILE", false);
|
||||
bool stats = get_env("ROCPROF_STATS", false);
|
||||
bool stats_summary = get_env("ROCPROF_STATS_SUMMARY", false);
|
||||
bool stats_summary_per_domain = get_env("ROCPROF_STATS_SUMMARY_PER_DOMAIN", false);
|
||||
bool csv_output = false;
|
||||
bool json_output = false;
|
||||
bool pftrace_output = false;
|
||||
bool otf2_output = false;
|
||||
bool summary_output = false;
|
||||
bool kernel_rename = get_env("ROCPROF_KERNEL_RENAME", false);
|
||||
int mpi_size = get_mpi_size();
|
||||
int mpi_rank = get_mpi_rank();
|
||||
size_t perfetto_shmem_size_hint = get_env("ROCPROF_PERFETTO_SHMEM_SIZE_HINT_KB", 64);
|
||||
size_t perfetto_buffer_size = get_env("ROCPROF_PERFETTO_BUFFER_SIZE_KB", 1024000);
|
||||
std::string output_path = get_env("ROCPROF_OUTPUT_PATH", fs::current_path().string());
|
||||
std::string output_file = get_env("ROCPROF_OUTPUT_FILE_NAME", std::to_string(getpid()));
|
||||
std::string tmp_directory = get_env("ROCPROF_TMPDIR", output_path);
|
||||
uint64_t stats_summary_unit_value = 1;
|
||||
std::string stats_summary_unit = get_env("ROCPROF_STATS_SUMMARY_UNITS", "nsec");
|
||||
std::string output_path = get_env("ROCPROF_OUTPUT_PATH", fs::current_path().string());
|
||||
std::string output_file =
|
||||
get_env("ROCPROF_OUTPUT_FILE_NAME", fmt::format("%hostname%/{}", getpid()));
|
||||
std::string tmp_directory = get_env("ROCPROF_TMPDIR", output_path);
|
||||
std::string stats_summary_file = get_env("ROCPROF_STATS_SUMMARY_OUTPUT", "stderr");
|
||||
|
||||
std::string kernel_filter_include =
|
||||
get_env("ROCPROF_KERNEL_FILTER_INCLUDE_REGEX", std::string{".*"});
|
||||
@@ -94,11 +122,68 @@ struct config
|
||||
std::string perfetto_buffer_fill_policy =
|
||||
get_env("ROCPROF_PERFETTO_BUFFER_FILL_POLICY", std::string{"discard"});
|
||||
std::string perfetto_backend = get_env("ROCPROF_PERFETTO_BACKEND", std::string{"inprocess"});
|
||||
std::unordered_set<uint32_t> kernel_filter_range = {};
|
||||
std::set<std::string> counters = {};
|
||||
std::unordered_set<uint32_t> kernel_filter_range = {};
|
||||
std::set<std::string> counters = {};
|
||||
std::vector<std::string> stats_summary_groups = {};
|
||||
|
||||
template <typename ArchiveT>
|
||||
void save(ArchiveT&) const;
|
||||
|
||||
template <typename ArchiveT>
|
||||
void load(ArchiveT&)
|
||||
{}
|
||||
};
|
||||
|
||||
template <config_context ContextT = config_context::global>
|
||||
template <typename ArchiveT>
|
||||
void
|
||||
config::save(ArchiveT& ar) const
|
||||
{
|
||||
#define CFG_SERIALIZE_MEMBER(VAR) ar(cereal::make_nvp(#VAR, VAR))
|
||||
#define CFG_SERIALIZE_NAMED_MEMBER(NAME, VAR) ar(cereal::make_nvp(NAME, VAR))
|
||||
|
||||
CFG_SERIALIZE_MEMBER(demangle);
|
||||
CFG_SERIALIZE_MEMBER(truncate);
|
||||
CFG_SERIALIZE_MEMBER(kernel_trace);
|
||||
CFG_SERIALIZE_MEMBER(hsa_core_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(hsa_amd_ext_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(hsa_image_ext_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(hsa_finalizer_ext_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(marker_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(memory_copy_trace);
|
||||
CFG_SERIALIZE_MEMBER(scratch_memory_trace);
|
||||
CFG_SERIALIZE_MEMBER(counter_collection);
|
||||
CFG_SERIALIZE_MEMBER(hip_runtime_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(hip_compiler_api_trace);
|
||||
CFG_SERIALIZE_MEMBER(kernel_rename);
|
||||
|
||||
CFG_SERIALIZE_NAMED_MEMBER("summary", stats_summary);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("summary_per_domain", stats_summary_per_domain);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("summary_groups", stats_summary_groups);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("summary_unit", stats_summary_unit);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("summary_file", stats_summary_file);
|
||||
|
||||
CFG_SERIALIZE_MEMBER(perfetto_shmem_size_hint);
|
||||
CFG_SERIALIZE_MEMBER(perfetto_buffer_size);
|
||||
CFG_SERIALIZE_MEMBER(perfetto_buffer_fill_policy);
|
||||
CFG_SERIALIZE_MEMBER(perfetto_backend);
|
||||
|
||||
CFG_SERIALIZE_NAMED_MEMBER("raw_tmp_directory", tmp_directory);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("raw_output_path", output_path);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("raw_output_file", output_file);
|
||||
CFG_SERIALIZE_NAMED_MEMBER("tmp_directory", format(tmp_directory));
|
||||
CFG_SERIALIZE_NAMED_MEMBER("output_path", format(output_path));
|
||||
CFG_SERIALIZE_NAMED_MEMBER("output_file", format(output_file));
|
||||
|
||||
CFG_SERIALIZE_MEMBER(counters);
|
||||
CFG_SERIALIZE_MEMBER(kernel_filter_include);
|
||||
CFG_SERIALIZE_MEMBER(kernel_filter_exclude);
|
||||
CFG_SERIALIZE_MEMBER(kernel_filter_range);
|
||||
|
||||
#undef CFG_SERIALIZE_MEMBER
|
||||
#undef CFG_SERIALIZE_NAMED_MEMBER
|
||||
}
|
||||
|
||||
template <config_context ContextT>
|
||||
config&
|
||||
get_config()
|
||||
{
|
||||
@@ -119,6 +204,11 @@ struct output_key
|
||||
{
|
||||
output_key(std::string _key, std::string _val, std::string _desc = {});
|
||||
|
||||
template <typename Tp,
|
||||
typename Up = Tp,
|
||||
std::enable_if_t<!common::mpl::is_string_type<Up>::value, int> = 0>
|
||||
output_key(std::string _key, Tp&& _val, std::string _desc = {});
|
||||
|
||||
operator std::pair<std::string, std::string>() const;
|
||||
|
||||
std::string key = {};
|
||||
@@ -126,16 +216,14 @@ struct output_key
|
||||
std::string description = {};
|
||||
};
|
||||
|
||||
template <typename Tp, typename Up, std::enable_if_t<!common::mpl::is_string_type<Up>::value, int>>
|
||||
output_key::output_key(std::string _key, Tp&& _val, std::string _desc)
|
||||
: key{std::move(_key)}
|
||||
, value{fmt::format("{}", std::forward<Tp>(_val))}
|
||||
, description{std::move(_desc)}
|
||||
{}
|
||||
|
||||
std::vector<output_key>
|
||||
output_keys(std::string _tag = {});
|
||||
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag = {});
|
||||
|
||||
std::string
|
||||
format_name(std::string_view _name, const config& = get_config<>());
|
||||
|
||||
void
|
||||
initialize();
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -37,13 +37,13 @@ struct domain_type_name;
|
||||
static constexpr auto filename = FILENAME; \
|
||||
};
|
||||
|
||||
DEFINE_BUFFER_TYPE_NAME(HSA, "HSA_API", "hsa_trace")
|
||||
DEFINE_BUFFER_TYPE_NAME(HIP, "HIP_API", "hip_trace")
|
||||
DEFINE_BUFFER_TYPE_NAME(MEMORY_COPY, "MEMORY_COPY", "memory_copy")
|
||||
DEFINE_BUFFER_TYPE_NAME(COUNTER_COLLECTION, "COUNTER_COLLECTION", "counter_collection")
|
||||
DEFINE_BUFFER_TYPE_NAME(HSA, "HSA_API", "hsa_api")
|
||||
DEFINE_BUFFER_TYPE_NAME(HIP, "HIP_API", "hip_api")
|
||||
DEFINE_BUFFER_TYPE_NAME(MARKER, "MARKER_API", "marker_api")
|
||||
DEFINE_BUFFER_TYPE_NAME(KERNEL_DISPATCH, "KERNEL_DISPATCH", "kernel_dispatch")
|
||||
DEFINE_BUFFER_TYPE_NAME(MARKER, "MARKER", "marker_trace")
|
||||
DEFINE_BUFFER_TYPE_NAME(MEMORY_COPY, "MEMORY_COPY", "memory_copy")
|
||||
DEFINE_BUFFER_TYPE_NAME(SCRATCH_MEMORY, "SCRATCH_MEMORY", "scratch_memory")
|
||||
DEFINE_BUFFER_TYPE_NAME(COUNTER_COLLECTION, "COUNTER_COLLECTION", "counter_collection")
|
||||
|
||||
#undef DEFINE_BUFFER_TYPE_NAME
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ enum class domain_type
|
||||
{
|
||||
HSA = 0,
|
||||
HIP,
|
||||
MEMORY_COPY,
|
||||
COUNTER_COLLECTION,
|
||||
KERNEL_DISPATCH,
|
||||
MARKER,
|
||||
KERNEL_DISPATCH,
|
||||
MEMORY_COPY,
|
||||
SCRATCH_MEMORY,
|
||||
COUNTER_COLLECTION,
|
||||
LAST,
|
||||
};
|
||||
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "generateCSV.hpp"
|
||||
#include "config.hpp"
|
||||
#include "csv.hpp"
|
||||
#include "generateStats.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/config.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
@@ -41,47 +42,6 @@ namespace tool
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using stats_data_t = statistics<uint64_t, float_type>;
|
||||
using stats_map_t = std::map<std::string_view, stats_data_t>;
|
||||
|
||||
struct percentage
|
||||
{
|
||||
float_type value = {};
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, percentage val) { return (os << val.value); }
|
||||
};
|
||||
|
||||
struct stats_formatter
|
||||
{
|
||||
template <typename Tp>
|
||||
std::ostream& operator()(std::ostream& ofs, const Tp& _val) const
|
||||
{
|
||||
using value_type = common::mpl::unqualified_type_t<Tp>;
|
||||
|
||||
if constexpr(std::is_floating_point<value_type>::value)
|
||||
{
|
||||
constexpr value_type one_hundredth = 1.0e-2;
|
||||
if(_val > one_hundredth)
|
||||
ofs << std::setprecision(6) << std::fixed;
|
||||
else
|
||||
ofs << std::setprecision(8) << std::scientific;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, percentage>::value)
|
||||
{
|
||||
constexpr float_type one = 1.0;
|
||||
constexpr float_type one_hundredth = 1.0e-2;
|
||||
if(_val.value >= one)
|
||||
ofs << std::setprecision(2) << std::fixed;
|
||||
else if(_val.value > one_hundredth)
|
||||
ofs << std::setprecision(4) << std::fixed;
|
||||
else
|
||||
ofs << std::setprecision(3) << std::scientific;
|
||||
}
|
||||
|
||||
return ofs;
|
||||
}
|
||||
};
|
||||
|
||||
tool::output_file
|
||||
get_stats_output_file(std::string name)
|
||||
{
|
||||
@@ -99,10 +59,10 @@ get_stats_output_file(std::string name)
|
||||
}};
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
write_stats(output_file&& ofs, const stats_map_t& data_v)
|
||||
void
|
||||
write_stats(output_file&& ofs, const stats_entry_vec_t& data_v)
|
||||
{
|
||||
auto data = std::vector<std::pair<std::string_view, stats_data_t>>{};
|
||||
auto data = stats_entry_vec_t{};
|
||||
auto _duration = stats_data_t{};
|
||||
for(const auto& [id, value] : data_v)
|
||||
{
|
||||
@@ -136,8 +96,6 @@ write_stats(output_file&& ofs, const stats_map_t& data_v)
|
||||
value.get_stddev());
|
||||
ofs << _row.str() << std::flush;
|
||||
}
|
||||
|
||||
return _duration;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -275,14 +233,17 @@ generate_csv(tool_table* /*tool_functions*/, std::vector<rocprofiler_agent_v0_t>
|
||||
}
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
auto kernel_stats = stats_map_t{};
|
||||
auto ofs = tool::output_file{"kernel_trace",
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("kernel_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"kernel_trace",
|
||||
tool::csv::kernel_trace_csv_encoder{},
|
||||
{"Kind",
|
||||
"Agent_Id",
|
||||
@@ -329,27 +290,21 @@ generate_csv(tool_table*
|
||||
record.dispatch_info.grid_size.y,
|
||||
record.dispatch_info.grid_size.z);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
kernel_stats[kernel_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
_duration = write_stats(get_stats_output_file("kernel_stats"), kernel_stats);
|
||||
|
||||
return _duration;
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
auto hip_stats = stats_map_t{};
|
||||
auto ofs = tool::output_file{"hip_api_trace",
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("hip_api_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"hip_api_trace",
|
||||
tool::csv::api_csv_encoder{},
|
||||
{"Domain",
|
||||
"Function",
|
||||
@@ -372,28 +327,21 @@ generate_csv(tool_table* tool
|
||||
record.start_timestamp,
|
||||
record.end_timestamp);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
hip_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
{
|
||||
_duration = write_stats(get_stats_output_file("hip_stats"), hip_stats);
|
||||
}
|
||||
return _duration;
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
auto hsa_stats = stats_map_t{};
|
||||
auto ofs = tool::output_file{"hsa_api_trace",
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("hsa_api_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"hsa_api_trace",
|
||||
tool::csv::api_csv_encoder{},
|
||||
{"Domain",
|
||||
"Function",
|
||||
@@ -417,28 +365,21 @@ generate_csv(tool_table* tool
|
||||
record.start_timestamp,
|
||||
record.end_timestamp);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
hsa_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
{
|
||||
_duration = write_stats(get_stats_output_file("hsa_stats"), hsa_stats);
|
||||
}
|
||||
return _duration;
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
auto memory_copy_stats = stats_map_t{};
|
||||
auto ofs = tool::output_file{"memory_copy_trace",
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("memory_copy_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"memory_copy_trace",
|
||||
tool::csv::memory_copy_csv_encoder{},
|
||||
{"Kind",
|
||||
"Direction",
|
||||
@@ -461,28 +402,21 @@ generate_csv(tool_table*
|
||||
record.start_timestamp,
|
||||
record.end_timestamp);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
memory_copy_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
{
|
||||
_duration = write_stats(get_stats_output_file("memory_copy_stats"), memory_copy_stats);
|
||||
}
|
||||
return _duration;
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
auto marker_stats = stats_map_t{};
|
||||
auto ofs = tool::output_file{"marker_api_trace",
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("marker_api_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"marker_api_trace",
|
||||
tool::csv::marker_csv_encoder{},
|
||||
{"Domain",
|
||||
"Function",
|
||||
@@ -518,25 +452,19 @@ generate_csv(tool_table* t
|
||||
record.start_timestamp,
|
||||
record.end_timestamp);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
marker_stats[_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
{
|
||||
_duration = write_stats(get_stats_output_file("marker_stats"), marker_stats);
|
||||
}
|
||||
return _duration;
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& data)
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("counter_collection_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"counter_collection",
|
||||
tool::csv::counter_collection_csv_encoder{},
|
||||
@@ -601,14 +529,17 @@ generate_csv(tool_table* too
|
||||
}
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
return stats_data_t{};
|
||||
}
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data)
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data,
|
||||
const stats_entry_t& stats)
|
||||
{
|
||||
if(data.empty()) return stats_data_t{};
|
||||
if(data.empty()) return;
|
||||
|
||||
if(tool::get_config().stats && stats)
|
||||
write_stats(get_stats_output_file("scratch_memory_stats"), stats.entries);
|
||||
|
||||
auto ofs = tool::output_file{"scratch_memory_trace",
|
||||
tool::csv::scratch_memory_encoder{},
|
||||
@@ -623,7 +554,6 @@ generate_csv(tool_table*
|
||||
"End_Timestamp",
|
||||
}};
|
||||
|
||||
auto scratch_memory_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto row_ss = std::stringstream{};
|
||||
@@ -641,45 +571,38 @@ generate_csv(tool_table*
|
||||
record.start_timestamp,
|
||||
record.end_timestamp);
|
||||
|
||||
if(tool::get_config().stats)
|
||||
scratch_memory_stats[op_name] += (record.end_timestamp - record.start_timestamp);
|
||||
|
||||
ofs << row_ss.str();
|
||||
}
|
||||
|
||||
auto _duration = stats_data_t{};
|
||||
if(tool::get_config().stats)
|
||||
{
|
||||
_duration =
|
||||
write_stats(get_stats_output_file("scratch_memory_stats"), scratch_memory_stats);
|
||||
}
|
||||
return _duration;
|
||||
}
|
||||
|
||||
void
|
||||
generate_csv(tool_table* /*tool_functions*/, std::unordered_map<domain_type, stats_data_t>& data)
|
||||
generate_csv(tool_table* /*tool_functions*/, const domain_stats_vec_t& data_v)
|
||||
{
|
||||
using csv_encoder_t = rocprofiler::tool::csv::stats_csv_encoder;
|
||||
|
||||
if(!tool::get_config().stats) return;
|
||||
|
||||
auto _data = data_v;
|
||||
auto _total_stats = stats_data_t{};
|
||||
for(const auto& itr : data)
|
||||
_total_stats += itr.second;
|
||||
for(const auto& itr : _data)
|
||||
_total_stats += itr.second.total;
|
||||
|
||||
if(_total_stats.get_count() == 0) return;
|
||||
|
||||
std::sort(_data.begin(), _data.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return (lhs.second.total.get_sum() > rhs.second.total.get_sum());
|
||||
});
|
||||
|
||||
auto ofs = get_stats_output_file("domain_stats");
|
||||
|
||||
constexpr float_type one_hundred = 100.0;
|
||||
const float_type _total_duration = _total_stats.get_sum();
|
||||
for(const auto& [type, value] : data)
|
||||
const float_type _total_duration = _total_stats.get_sum();
|
||||
for(const auto& [type, value] : _data)
|
||||
{
|
||||
auto name = get_domain_column_name(type);
|
||||
auto duration_ns = value.get_sum();
|
||||
auto calls = value.get_count();
|
||||
float_type avg_ns = value.get_mean();
|
||||
float_type percent_v = (duration_ns / _total_duration) * one_hundred;
|
||||
auto name = get_domain_column_name(type);
|
||||
auto duration_ns = value.total.get_sum();
|
||||
auto calls = value.total.get_count();
|
||||
auto avg_ns = value.total.get_mean();
|
||||
auto percent_v = value.total.get_percent(_total_duration);
|
||||
|
||||
auto _row = std::stringstream{};
|
||||
csv_encoder_t::write_row<stats_formatter>(_row,
|
||||
@@ -688,9 +611,9 @@ generate_csv(tool_table* /*tool_functions*/, std::unordered_map<domain_type, sta
|
||||
duration_ns,
|
||||
avg_ns,
|
||||
percentage{percent_v},
|
||||
value.get_min(),
|
||||
value.get_max(),
|
||||
value.get_stddev());
|
||||
value.total.get_min(),
|
||||
value.total.get_max(),
|
||||
value.total.get_stddev());
|
||||
ofs << _row.str() << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "generateStats.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
@@ -31,41 +32,45 @@ namespace rocprofiler
|
||||
{
|
||||
namespace tool
|
||||
{
|
||||
using float_type = double;
|
||||
using stats_data_t = statistics<uint64_t, float_type>;
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions, std::vector<rocprofiler_agent_v0_t>& data);
|
||||
|
||||
stats_data_t
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& data);
|
||||
|
||||
stats_data_t
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data);
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions, std::unordered_map<domain_type, stats_data_t>& data);
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data,
|
||||
const stats_entry_t& stats);
|
||||
|
||||
void
|
||||
generate_csv(tool_table* tool_functions, const domain_stats_vec_t& data);
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
#include "config.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "output_file.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
#include "lib/common/string_entry.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
@@ -39,6 +41,7 @@ namespace tool
|
||||
void
|
||||
write_json(tool_table* tool_functions,
|
||||
uint64_t pid,
|
||||
const domain_stats_vec_t& domain_stats,
|
||||
std::vector<rocprofiler_agent_v0_t> agent_data,
|
||||
std::vector<rocprofiler_tool_counter_info_t> counter_data,
|
||||
std::deque<rocprofiler_buffer_tracing_hip_api_record_t>* hip_api_deque,
|
||||
@@ -52,14 +55,14 @@ write_json(tool_table* tool
|
||||
{
|
||||
using JSONOutputArchive = cereal::MinimalJSONOutputArchive;
|
||||
|
||||
constexpr auto json_prec = 32;
|
||||
constexpr auto json_indent = JSONOutputArchive::Options::IndentChar::space;
|
||||
auto json_opts = JSONOutputArchive::Options{json_prec, json_indent, 1};
|
||||
auto filename = std::string_view{"results"};
|
||||
auto [output_stream, cleanup] = get_output_stream(filename, ".json");
|
||||
constexpr auto json_prec = 32;
|
||||
constexpr auto json_indent = JSONOutputArchive::Options::IndentChar::space;
|
||||
auto json_opts = JSONOutputArchive::Options{json_prec, json_indent, 1};
|
||||
auto filename = std::string_view{"results"};
|
||||
auto ofs = get_output_stream(filename, ".json");
|
||||
|
||||
{
|
||||
auto json_ar = JSONOutputArchive{*output_stream, json_opts};
|
||||
auto json_ar = JSONOutputArchive{*ofs.stream, json_opts};
|
||||
json_ar.setNextName("rocprofiler-sdk-tool");
|
||||
json_ar.startNode();
|
||||
|
||||
@@ -74,6 +77,29 @@ write_json(tool_table* tool
|
||||
json_ar(cereal::make_nvp("pid", pid));
|
||||
json_ar(cereal::make_nvp("init_time", timestamps->app_start_time));
|
||||
json_ar(cereal::make_nvp("fini_time", timestamps->app_end_time));
|
||||
json_ar(cereal::make_nvp("config", get_config()));
|
||||
json_ar(cereal::make_nvp("command", common::read_command_line(getpid())));
|
||||
json_ar.finishNode();
|
||||
}
|
||||
|
||||
// summary
|
||||
{
|
||||
json_ar.setNextName("summary");
|
||||
json_ar.startNode();
|
||||
json_ar.makeArray();
|
||||
|
||||
for(const auto& itr : domain_stats)
|
||||
{
|
||||
auto _name = get_domain_column_name(itr.first);
|
||||
json_ar.startNode();
|
||||
|
||||
json_ar(cereal::make_nvp("domain", std::string{_name}));
|
||||
json_ar(cereal::make_nvp("stats", itr.second));
|
||||
// itr.second.serialize(json_ar, 0);
|
||||
|
||||
json_ar.finishNode();
|
||||
}
|
||||
|
||||
json_ar.finishNode();
|
||||
}
|
||||
|
||||
@@ -154,8 +180,7 @@ write_json(tool_table* tool
|
||||
json_ar.finishNode();
|
||||
}
|
||||
|
||||
*output_stream << std::flush;
|
||||
if(cleanup) cleanup(output_stream);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "helper.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
@@ -31,6 +32,7 @@ namespace tool
|
||||
void
|
||||
write_json(tool_table* tool_functions,
|
||||
uint64_t pid,
|
||||
const domain_stats_vec_t& domain_stats,
|
||||
std::vector<rocprofiler_agent_v0_t> agent_data,
|
||||
std::vector<rocprofiler_tool_counter_info_t> counter_data,
|
||||
std::deque<rocprofiler_buffer_tracing_hip_api_record_t>* hip_api_deque,
|
||||
|
||||
@@ -21,13 +21,14 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "generateOTF2.hpp"
|
||||
#include "config.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "output_file.hpp"
|
||||
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/mpl.hpp"
|
||||
#include "lib/common/units.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/config.hpp"
|
||||
#include "output_file.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
@@ -510,6 +511,10 @@ write_otf2(tool_table* tool
|
||||
if(!_inp) return;
|
||||
for(auto itr : *_inp)
|
||||
{
|
||||
if(itr.kind == ROCPROFILER_BUFFER_TRACING_MARKER_CORE_API &&
|
||||
itr.operation == ROCPROFILER_MARKER_CORE_API_ID_roctxMarkA)
|
||||
continue;
|
||||
|
||||
using value_type = common::mpl::unqualified_type_t<decltype(itr)>;
|
||||
auto name = buffer_names.at(itr.kind, itr.operation);
|
||||
auto paradigm = OTF2_PARADIGM_HIP;
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "generatePerfetto.hpp"
|
||||
#include "config.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "output_file.hpp"
|
||||
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/config.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
@@ -503,23 +503,20 @@ write_perfetto(
|
||||
tracing_session->FlushBlocking();
|
||||
tracing_session->StopBlocking();
|
||||
|
||||
auto filename = std::string{"results"};
|
||||
auto cleanup = std::function<void(std::ostream*&)>{};
|
||||
std::ostream* ofs = nullptr;
|
||||
|
||||
std::tie(ofs, cleanup) = get_output_stream(filename, ".pftrace");
|
||||
auto filename = std::string{"results"};
|
||||
auto ofs = get_output_stream(filename, ".pftrace");
|
||||
|
||||
auto amount_read = std::atomic<size_t>{0};
|
||||
auto is_done = std::promise<void>{};
|
||||
auto _mtx = std::mutex{};
|
||||
auto _reader = [ofs, &_mtx, &is_done, &amount_read](
|
||||
auto _reader = [&ofs, &_mtx, &is_done, &amount_read](
|
||||
::perfetto::TracingSession::ReadTraceCallbackArgs _args) {
|
||||
auto _lk = std::unique_lock<std::mutex>{_mtx};
|
||||
if(_args.data && _args.size > 0)
|
||||
{
|
||||
ROCP_TRACE << "Writing " << _args.size << " B to trace...";
|
||||
// Write the trace data into file
|
||||
ofs->write(_args.data, _args.size);
|
||||
ofs.stream->write(_args.data, _args.size);
|
||||
amount_read += _args.size;
|
||||
}
|
||||
ROCP_INFO_IF(!_args.has_more && amount_read > 0)
|
||||
@@ -540,10 +537,10 @@ write_perfetto(
|
||||
tracing_session.reset();
|
||||
|
||||
ROCP_TRACE << "Flushing trace output stream...";
|
||||
(*ofs) << std::flush;
|
||||
(*ofs.stream) << std::flush;
|
||||
|
||||
ROCP_TRACE << "Destroying trace output stream...";
|
||||
if(cleanup) cleanup(ofs);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// 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 "generateStats.hpp"
|
||||
#include "config.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "lib/common/logging.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/domain_type.hpp"
|
||||
#include "output_file.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace tool
|
||||
{
|
||||
namespace
|
||||
{
|
||||
stats_entry_t
|
||||
get_stats(const stats_map_t& data_v)
|
||||
{
|
||||
auto _stats = stats_entry_t{};
|
||||
for(const auto& [id, value] : data_v)
|
||||
{
|
||||
_stats.entries.emplace_back(id, value);
|
||||
_stats.total += value;
|
||||
}
|
||||
|
||||
return _stats.sort();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data)
|
||||
{
|
||||
auto kernel_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto kernel_name = tool_functions->tool_get_kernel_name_fn(
|
||||
record.dispatch_info.kernel_id, record.correlation_id.external.value);
|
||||
|
||||
kernel_stats[kernel_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(kernel_stats);
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data)
|
||||
{
|
||||
auto hip_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto api_name = tool_functions->tool_get_operation_name_fn(record.kind, record.operation);
|
||||
hip_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(hip_stats);
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data)
|
||||
{
|
||||
auto hsa_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto api_name = tool_functions->tool_get_operation_name_fn(record.kind, record.operation);
|
||||
hsa_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(hsa_stats);
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data)
|
||||
{
|
||||
auto memory_copy_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto api_name = tool_functions->tool_get_operation_name_fn(record.kind, record.operation);
|
||||
memory_copy_stats[api_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(memory_copy_stats);
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data)
|
||||
{
|
||||
auto marker_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto _name = std::string_view{};
|
||||
|
||||
if(record.kind == ROCPROFILER_BUFFER_TRACING_MARKER_CORE_API &&
|
||||
(record.operation == ROCPROFILER_MARKER_CORE_API_ID_roctxMarkA ||
|
||||
record.operation == ROCPROFILER_MARKER_CORE_API_ID_roctxRangePushA ||
|
||||
record.operation == ROCPROFILER_MARKER_CORE_API_ID_roctxRangeStartA))
|
||||
{
|
||||
_name = tool_functions->tool_get_roctx_msg_fn(record.correlation_id.internal);
|
||||
}
|
||||
else
|
||||
{
|
||||
_name = tool_functions->tool_get_operation_name_fn(record.kind, record.operation);
|
||||
}
|
||||
|
||||
marker_stats[_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(marker_stats);
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* /*tool_functions*/,
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& /*data*/)
|
||||
{
|
||||
return stats_entry_t{};
|
||||
}
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data)
|
||||
{
|
||||
auto scratch_memory_stats = stats_map_t{};
|
||||
for(const auto& record : data)
|
||||
{
|
||||
auto op_name = tool_functions->tool_get_operation_name_fn(record.kind, record.operation);
|
||||
scratch_memory_stats[op_name] += (record.end_timestamp - record.start_timestamp);
|
||||
}
|
||||
|
||||
return get_stats(scratch_memory_stats);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void
|
||||
generate_stats(output_stream_t& os,
|
||||
std::string_view label,
|
||||
const domain_stats_vec_t& data_v,
|
||||
std::string_view indent_v)
|
||||
{
|
||||
auto _data = stats_entry_t{};
|
||||
auto _cols = std::unordered_map<std::string_view, domain_type>{};
|
||||
|
||||
auto _get_entry = [&_data, &_cols](domain_type _domain,
|
||||
std::string_view _key) -> stats_data_t* {
|
||||
for(auto& itr : _data.entries)
|
||||
{
|
||||
if(itr.first == _key) return &itr.second;
|
||||
}
|
||||
|
||||
_cols.emplace(_key, _domain);
|
||||
auto& itr = _data.entries.emplace_back(_key, stats_data_t{});
|
||||
return &itr.second;
|
||||
};
|
||||
|
||||
uint64_t name_width = 40;
|
||||
uint64_t domain_width = 12;
|
||||
for(const auto& itr : data_v)
|
||||
{
|
||||
for(const auto& eitr : itr.second.entries)
|
||||
{
|
||||
_data.total += eitr.second;
|
||||
auto* _entry = _get_entry(itr.first, eitr.first);
|
||||
*CHECK_NOTNULL(_entry) += eitr.second;
|
||||
name_width = std::max(name_width, eitr.first.length());
|
||||
}
|
||||
domain_width = std::max(domain_width, get_domain_column_name(itr.first).length());
|
||||
}
|
||||
|
||||
if(!_data) return;
|
||||
|
||||
std::sort(_data.entries.begin(), _data.entries.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return (lhs.second.get_sum() > rhs.second.get_sum());
|
||||
});
|
||||
|
||||
const float_type _total_duration = _data.total.get_sum();
|
||||
|
||||
os << fmt::format("\n{}ROCPROFV3 {}:\n\n", indent_v, label) << std::flush;
|
||||
|
||||
{
|
||||
auto _header = fmt::format(
|
||||
"| {:^{}} | {:^{}} | {:^15} | {:^15} | {:^15} | {:^13} | {:^15} | {:^15} | {:^15} |",
|
||||
"NAME",
|
||||
name_width,
|
||||
"DOMAIN",
|
||||
domain_width,
|
||||
"CALLS",
|
||||
fmt::format("DURATION ({})", tool::get_config().stats_summary_unit),
|
||||
fmt::format("AVERAGE ({})", tool::get_config().stats_summary_unit),
|
||||
"PERCENT (INC)",
|
||||
fmt::format("MIN ({})", tool::get_config().stats_summary_unit),
|
||||
fmt::format("MAX ({})", tool::get_config().stats_summary_unit),
|
||||
"STDDEV");
|
||||
(*os.stream) << indent_v << _header << "\n" << std::flush;
|
||||
|
||||
auto _div =
|
||||
fmt::format("|-{0:-^{1}}-|-{0:-^{2}}-|-{0:-^15}-|-{0:-^15}-|-{0:-^15}-|-{0:-^13}"
|
||||
"-|-{0:-^15}-|-{0:-^15}-|-{0:-^15}-|",
|
||||
"",
|
||||
name_width,
|
||||
domain_width);
|
||||
(*os.stream) << indent_v << _div << "\n" << std::flush;
|
||||
}
|
||||
|
||||
for(const auto& [type, value] : _data.entries)
|
||||
{
|
||||
auto name = type;
|
||||
auto duration_ns = value.get_sum();
|
||||
auto calls = value.get_count();
|
||||
auto avg_ns = value.get_mean();
|
||||
auto percent_v = value.get_percent(_total_duration);
|
||||
auto percent = std::to_string(percent_v);
|
||||
|
||||
auto _row = std::string{};
|
||||
|
||||
if(tool::get_config().stats_summary_unit_value > 1)
|
||||
{
|
||||
auto _unit_div = static_cast<double>(tool::get_config().stats_summary_unit_value);
|
||||
_row = fmt::format("{}| {:<{}} | {:<{}} | {:15} | {:15} | {:15.3e} | {:>13} | {:15} | "
|
||||
"{:15} | {:15.3e} |",
|
||||
indent_v,
|
||||
name,
|
||||
name_width,
|
||||
get_domain_column_name(_cols.at(name)),
|
||||
domain_width,
|
||||
calls,
|
||||
duration_ns / _unit_div,
|
||||
avg_ns / _unit_div,
|
||||
percent,
|
||||
value.get_min() / _unit_div,
|
||||
value.get_max() / _unit_div,
|
||||
value.get_stddev() / _unit_div);
|
||||
}
|
||||
else
|
||||
{
|
||||
_row = fmt::format("{}| {:<{}} | {:<{}} | {:15} | {:15} | {:15.3e} | {:>13} | {:15} | "
|
||||
"{:15} | {:15.3e} |",
|
||||
indent_v,
|
||||
name,
|
||||
name_width,
|
||||
get_domain_column_name(_cols.at(name)),
|
||||
domain_width,
|
||||
calls,
|
||||
duration_ns,
|
||||
avg_ns,
|
||||
percent,
|
||||
value.get_min(),
|
||||
value.get_max(),
|
||||
value.get_stddev());
|
||||
}
|
||||
|
||||
(*os.stream) << _row << "\n" << std::flush;
|
||||
}
|
||||
|
||||
(*os.stream) << "\n" << std::flush;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void
|
||||
generate_stats(tool_table* /*tool_functions*/, const domain_stats_vec_t& inp_data)
|
||||
{
|
||||
auto data_v = inp_data;
|
||||
|
||||
std::sort(data_v.begin(), data_v.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
|
||||
output_stream_t _os = get_output_stream(tool::get_config().stats_summary_file, ".txt");
|
||||
auto _indent = (_os.writes_to_file()) ? std::string_view{} : std::string_view{" "};
|
||||
|
||||
if(tool::get_config().stats_summary_per_domain)
|
||||
{
|
||||
for(const auto& itr : data_v)
|
||||
{
|
||||
if(!itr.second) continue;
|
||||
|
||||
auto _name = fmt::format("{} SUMMARY", get_domain_column_name(itr.first));
|
||||
auto _tmp = domain_stats_vec_t{};
|
||||
_tmp.emplace_back(itr.first, itr.second);
|
||||
generate_stats(_os, _name, _tmp, _indent);
|
||||
}
|
||||
}
|
||||
|
||||
if(!tool::get_config().stats_summary_groups.empty())
|
||||
{
|
||||
auto domain_groups = std::vector<domain_stats_vec_t>{};
|
||||
for(const auto& itr : tool::get_config().stats_summary_groups)
|
||||
{
|
||||
auto _names = std::vector<std::string>{};
|
||||
auto _tmp = domain_stats_vec_t{};
|
||||
for(const auto& ditr : data_v)
|
||||
{
|
||||
auto _col_name = get_domain_column_name(ditr.first);
|
||||
|
||||
if(std::regex_match(_col_name.data(), std::regex{itr}))
|
||||
{
|
||||
if(!ditr.second) continue;
|
||||
_names.emplace_back(_col_name);
|
||||
_tmp.emplace_back(ditr.first, ditr.second);
|
||||
}
|
||||
}
|
||||
|
||||
ROCP_CI_LOG_IF(WARNING, _names.empty())
|
||||
<< "summary group regex '" << itr << "' matched with zero domain groups";
|
||||
|
||||
auto _name = fmt::format("{} SUMMARY", fmt::join(_names.begin(), _names.end(), " + "));
|
||||
generate_stats(_os, _name, _tmp, _indent);
|
||||
}
|
||||
}
|
||||
|
||||
if(tool::get_config().stats_summary) generate_stats(_os, "SUMMARY", data_v, _indent);
|
||||
}
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,63 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "helper.hpp"
|
||||
#include "statistics.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace tool
|
||||
{
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hip_api_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_marker_api_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_tool_counter_collection_record_t>& data);
|
||||
|
||||
stats_entry_t
|
||||
generate_stats(tool_table* tool_functions,
|
||||
const std::deque<rocprofiler_buffer_tracing_scratch_memory_record_t>& data);
|
||||
|
||||
void
|
||||
generate_stats(tool_table* tool_functions, const domain_stats_vec_t& data);
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
@@ -33,6 +33,12 @@ namespace tool
|
||||
{
|
||||
namespace fs = common::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
const auto stdout_names = std::unordered_set<std::string_view>{"stdout", "STDOUT"};
|
||||
const auto stderr_names = std::unordered_set<std::string_view>{"stderr", "STDERR"};
|
||||
} // namespace
|
||||
|
||||
std::string
|
||||
get_output_filename(std::string_view fname, std::string_view ext)
|
||||
{
|
||||
@@ -55,16 +61,17 @@ get_output_filename(std::string_view fname, std::string_view ext)
|
||||
|
||||
return tool::format(output_path / fmt::format("{}_{}{}", output_prefix, fname, _ext));
|
||||
}
|
||||
std::pair<std::ostream*, output_stream_dtor_t>
|
||||
|
||||
output_stream_t
|
||||
get_output_stream(std::string_view fname, std::string_view ext)
|
||||
{
|
||||
auto cfg_output_path = tool::format(tool::get_config().output_path);
|
||||
|
||||
if(cfg_output_path == "stdout" || cfg_output_path == "STDOUT")
|
||||
if(stdout_names.count(cfg_output_path) > 0 || stdout_names.count(fname) > 0)
|
||||
return {&std::cout, [](auto*&) {}};
|
||||
else if(cfg_output_path == "stderr" || cfg_output_path == "STDERR")
|
||||
else if(stderr_names.count(cfg_output_path) > 0 || stderr_names.count(fname) > 0)
|
||||
return {&std::cout, [](auto*&) {}};
|
||||
else if(cfg_output_path.empty())
|
||||
else if(cfg_output_path.empty() || fname.empty())
|
||||
return {&std::clog, [](auto*&) {}};
|
||||
|
||||
auto output_file = get_output_filename(fname, ext);
|
||||
@@ -82,12 +89,12 @@ get_output_stream(std::string_view fname, std::string_view ext)
|
||||
|
||||
output_file::~output_file()
|
||||
{
|
||||
if(m_stream)
|
||||
if(m_os.stream)
|
||||
ROCP_INFO << "Closing result file: " << m_name;
|
||||
else
|
||||
ROCP_WARNING << "output_file::~output_file does not have a output stream instance!";
|
||||
|
||||
m_dtor(m_stream);
|
||||
m_os.close();
|
||||
}
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "csv.hpp"
|
||||
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/csv.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
@@ -41,12 +40,48 @@ namespace rocprofiler
|
||||
{
|
||||
namespace tool
|
||||
{
|
||||
using output_stream_dtor_t = void (*)(std::ostream*&);
|
||||
using ostream_dtor_t = void (*)(std::ostream*&);
|
||||
|
||||
using output_stream_pair_t = std::pair<std::ostream*, ostream_dtor_t>;
|
||||
|
||||
struct output_stream_t
|
||||
{
|
||||
output_stream_t() = default;
|
||||
output_stream_t(std::ostream* _os, ostream_dtor_t _dtor)
|
||||
: stream{_os}
|
||||
, dtor{_dtor}
|
||||
{}
|
||||
|
||||
~output_stream_t() { close(); }
|
||||
output_stream_t(const output_stream_t&) = delete;
|
||||
output_stream_t(output_stream_t&&) noexcept = default;
|
||||
output_stream_t& operator=(const output_stream_t&) = delete;
|
||||
output_stream_t& operator=(output_stream_t&&) noexcept = default;
|
||||
|
||||
explicit operator bool() const { return stream != nullptr; }
|
||||
|
||||
template <typename Tp>
|
||||
std::ostream& operator<<(Tp&& value)
|
||||
{
|
||||
return ((stream) ? *stream : std::cerr) << std::forward<Tp>(value) << std::flush;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if(stream) (*stream) << std::flush;
|
||||
if(dtor) dtor(stream);
|
||||
}
|
||||
|
||||
bool writes_to_file() const { return (dynamic_cast<std::ofstream*>(stream) != nullptr); }
|
||||
|
||||
std::ostream* stream = nullptr;
|
||||
ostream_dtor_t dtor = nullptr;
|
||||
};
|
||||
|
||||
std::string
|
||||
get_output_filename(std::string_view fname, std::string_view ext);
|
||||
|
||||
std::pair<std::ostream*, output_stream_dtor_t>
|
||||
output_stream_t
|
||||
get_output_stream(std::string_view fname, std::string_view ext);
|
||||
|
||||
struct output_file
|
||||
@@ -65,16 +100,15 @@ struct output_file
|
||||
std::ostream& operator<<(T&& value)
|
||||
{
|
||||
auto _lk = std::unique_lock<std::mutex>{m_mutex};
|
||||
return ((m_stream) ? *m_stream : std::cerr) << std::forward<T>(value) << std::flush;
|
||||
return ((m_os.stream) ? *m_os.stream : std::cerr) << std::forward<T>(value) << std::flush;
|
||||
}
|
||||
|
||||
operator bool() const { return m_stream != nullptr; }
|
||||
operator bool() const { return m_os.stream != nullptr; }
|
||||
|
||||
private:
|
||||
const std::string m_name = {};
|
||||
std::mutex m_mutex = {};
|
||||
std::ostream* m_stream = nullptr;
|
||||
output_stream_dtor_t m_dtor = [](std::ostream*&) {};
|
||||
const std::string m_name = {};
|
||||
std::mutex m_mutex = {};
|
||||
output_stream_t m_os = {};
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
@@ -82,9 +116,8 @@ output_file::output_file(std::string name,
|
||||
csv::csv_encoder<N> encoder,
|
||||
std::array<std::string_view, N>&& header)
|
||||
: m_name{std::move(name)}
|
||||
, m_os{get_output_stream(m_name, ".csv")}
|
||||
{
|
||||
std::tie(m_stream, m_dtor) = get_output_stream(m_name, ".csv");
|
||||
|
||||
for(auto& itr : header)
|
||||
{
|
||||
ROCP_FATAL_IF(itr.empty())
|
||||
@@ -92,7 +125,7 @@ output_file::output_file(std::string name,
|
||||
}
|
||||
|
||||
// write the csv header
|
||||
if(m_stream) encoder.write_row(*m_stream, header);
|
||||
if(m_os.stream) encoder.write_row(*m_os.stream, header);
|
||||
}
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// 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 "statistics.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace tool
|
||||
{
|
||||
template <typename Tp>
|
||||
std::ostream&
|
||||
stats_formatter::operator()(std::ostream& ofs, const Tp& _val) const
|
||||
{
|
||||
using value_type = common::mpl::unqualified_type_t<Tp>;
|
||||
|
||||
if constexpr(std::is_floating_point<value_type>::value)
|
||||
{
|
||||
constexpr value_type one_hundredth = 1.0e-2;
|
||||
if(_val > one_hundredth)
|
||||
ofs << std::setprecision(6) << std::fixed;
|
||||
else
|
||||
ofs << std::setprecision(8) << std::scientific;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, percentage>::value)
|
||||
{
|
||||
constexpr float_type one = 1.0;
|
||||
constexpr float_type one_hundredth = 1.0e-2;
|
||||
if(_val.value >= one)
|
||||
ofs << std::setprecision(2) << std::fixed;
|
||||
else if(_val.value > one_hundredth)
|
||||
ofs << std::setprecision(4) << std::fixed;
|
||||
else
|
||||
ofs << std::setprecision(3) << std::scientific;
|
||||
}
|
||||
|
||||
return ofs;
|
||||
}
|
||||
|
||||
#define STATS_FORMATTER_INSTANTIATE_TEMPLATE(TYPE) \
|
||||
template std::ostream& stats_formatter::operator()(std::ostream&, const TYPE&) const;
|
||||
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(std::string)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(std::string_view)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(percentage)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(float)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(double)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(uint8_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(uint16_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(uint32_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(uint64_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(int8_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(int16_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(int32_t)
|
||||
STATS_FORMATTER_INSTANTIATE_TEMPLATE(int64_t)
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
@@ -22,6 +22,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "domain_type.hpp"
|
||||
|
||||
#include "lib/common/logging.hpp"
|
||||
#include "lib/common/mpl.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/cxx/serialization.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
@@ -29,7 +36,9 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
@@ -93,6 +102,8 @@ public:
|
||||
}
|
||||
|
||||
float_type get_stddev() const { return ::std::sqrt(::std::abs(get_variance())); }
|
||||
float_type get_percent(float_type _total) const;
|
||||
float_type get_percent(const this_type&) const;
|
||||
|
||||
// Modifications
|
||||
void reset()
|
||||
@@ -209,6 +220,107 @@ public:
|
||||
{
|
||||
return statistics(lhs) -= rhs;
|
||||
}
|
||||
|
||||
template <typename ArchiveT>
|
||||
void serialize(ArchiveT& ar, const unsigned int) const
|
||||
{
|
||||
ar(cereal::make_nvp("count", m_cnt));
|
||||
ar(cereal::make_nvp("sum", m_sum));
|
||||
ar(cereal::make_nvp("sqr", m_sqr));
|
||||
ar(cereal::make_nvp("min", m_min));
|
||||
ar(cereal::make_nvp("max", m_max));
|
||||
ar(cereal::make_nvp("mean", get_mean()));
|
||||
ar(cereal::make_nvp("stddev", get_stddev()));
|
||||
ar(cereal::make_nvp("variance", get_variance()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tp, typename Fp>
|
||||
typename statistics<Tp, Fp>::float_type
|
||||
statistics<Tp, Fp>::get_percent(float_type _total) const
|
||||
{
|
||||
constexpr float_type one_hundred = 100.0;
|
||||
const float_type _sum = get_sum();
|
||||
|
||||
ROCP_WARNING_IF(static_cast<int64_t>(_sum) > static_cast<int64_t>(_total))
|
||||
<< "percentage calculation > 100%. sum=" << _sum << " > total=" << _total;
|
||||
|
||||
return (_sum / _total) * one_hundred;
|
||||
}
|
||||
|
||||
template <typename Tp, typename Fp>
|
||||
typename statistics<Tp, Fp>::float_type
|
||||
statistics<Tp, Fp>::get_percent(const statistics<Tp, Fp>& _rhs) const
|
||||
{
|
||||
return get_percent(_rhs.get_sum());
|
||||
}
|
||||
|
||||
using float_type = double;
|
||||
using stats_data_t = statistics<uint64_t, float_type>;
|
||||
using stats_map_t = std::map<std::string_view, stats_data_t>;
|
||||
using stats_pair_t = std::pair<std::string_view, stats_data_t>;
|
||||
using stats_entry_vec_t = std::vector<stats_pair_t>;
|
||||
|
||||
inline bool
|
||||
default_stats_sorter(const stats_pair_t& lhs, const stats_pair_t& rhs)
|
||||
{
|
||||
return (lhs.second.get_sum() > rhs.second.get_sum());
|
||||
}
|
||||
|
||||
struct stats_entry_t
|
||||
{
|
||||
using sort_predicate_t = bool (*)(const stats_pair_t&, const stats_pair_t&);
|
||||
|
||||
stats_entry_t() = default;
|
||||
~stats_entry_t() = default;
|
||||
stats_entry_t(const stats_entry_t&) = default;
|
||||
stats_entry_t(stats_entry_t&&) noexcept = default;
|
||||
stats_entry_t& operator=(const stats_entry_t&) = default;
|
||||
stats_entry_t& operator=(stats_entry_t&&) noexcept = default;
|
||||
|
||||
template <typename FuncT = sort_predicate_t>
|
||||
stats_entry_t& sort(FuncT&& _predicate = default_stats_sorter);
|
||||
|
||||
explicit operator bool() const { return (total.get_count() > 0 && !entries.empty()); }
|
||||
|
||||
stats_data_t total = {};
|
||||
stats_entry_vec_t entries = {};
|
||||
|
||||
template <typename ArchiveT>
|
||||
void serialize(ArchiveT& ar, const unsigned int) const
|
||||
{
|
||||
total.serialize(ar, 0);
|
||||
auto _entries_map = std::map<std::string, stats_data_t>{};
|
||||
for(const auto& itr : entries)
|
||||
_entries_map.emplace(std::string{itr.first}, itr.second);
|
||||
ar(cereal::make_nvp("operations", _entries_map));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FuncT>
|
||||
stats_entry_t&
|
||||
stats_entry_t::sort(FuncT&& _predicate)
|
||||
{
|
||||
std::sort(entries.begin(), entries.end(), std::forward<FuncT>(_predicate));
|
||||
return *this;
|
||||
}
|
||||
|
||||
using domain_stats_t = std::pair<domain_type, stats_entry_t>;
|
||||
using domain_stats_vec_t = std::vector<domain_stats_t>;
|
||||
|
||||
struct stats_formatter
|
||||
{
|
||||
template <typename Tp>
|
||||
std::ostream& operator()(std::ostream& ofs, const Tp& _val) const;
|
||||
};
|
||||
|
||||
struct percentage
|
||||
{
|
||||
float_type value = {};
|
||||
friend std::ostream& operator<<(std::ostream& os, percentage val)
|
||||
{
|
||||
return (stats_formatter{}(os, val) << val.value);
|
||||
}
|
||||
};
|
||||
} // namespace tool
|
||||
} // namespace rocprofiler
|
||||
@@ -228,4 +340,12 @@ min(::rocprofiler::tool::statistics<Tp> lhs, const Tp& rhs)
|
||||
{
|
||||
return lhs.get_min(rhs);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(::rocprofiler::tool::percentage val)
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << val;
|
||||
return _ss.str();
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "domain_type.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "tmp_file.hpp"
|
||||
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template <typename Tp>
|
||||
@@ -71,15 +73,60 @@ void
|
||||
write_ring_buffer(Tp _v, domain_type type)
|
||||
{
|
||||
auto [_tmp_buf, _tmp_file] = get_tmp_file_buffer<ring_buffer_t<Tp>>(type);
|
||||
if(_tmp_buf->capacity() == 0) return;
|
||||
|
||||
if(_tmp_buf->capacity() == 0)
|
||||
{
|
||||
ROCP_INFO << "rocprofv3 is dropping record from domain " << get_domain_column_name(type)
|
||||
<< ". Buffer has a capacity of zero.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto* ptr = _tmp_buf->request(false);
|
||||
if(ptr == nullptr)
|
||||
{
|
||||
offload_buffer<ring_buffer_t<Tp>>(type);
|
||||
ptr = _tmp_buf->request(false);
|
||||
CHECK(ptr != nullptr);
|
||||
|
||||
// if failed, try again
|
||||
if(!ptr) ptr = _tmp_buf->request(false);
|
||||
|
||||
// after second failure, emit warning message
|
||||
ROCP_CI_LOG_IF(WARNING, !ptr)
|
||||
<< "rocprofv3 is dropping record from domain " << get_domain_column_name(type)
|
||||
<< ". No space in buffer: "
|
||||
<< fmt::format(
|
||||
"capacity={}, record_size={}, used_count={}, free_count={} | raw_info=[{}]",
|
||||
_tmp_buf->capacity(),
|
||||
_tmp_buf->data_size(),
|
||||
_tmp_buf->count(),
|
||||
_tmp_buf->free(),
|
||||
_tmp_buf->as_string());
|
||||
}
|
||||
|
||||
if(ptr)
|
||||
{
|
||||
if constexpr(std::is_move_constructible<Tp>::value)
|
||||
{
|
||||
new(ptr) Tp{std::move(_v)};
|
||||
}
|
||||
else if constexpr(std::is_move_assignable<Tp>::value)
|
||||
{
|
||||
*ptr = std::move(_v);
|
||||
}
|
||||
else if constexpr(std::is_copy_constructible<Tp>::value)
|
||||
{
|
||||
new(ptr) Tp{_v};
|
||||
}
|
||||
else if constexpr(std::is_copy_assignable<Tp>::value)
|
||||
{
|
||||
*ptr = _v;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::is_void<Tp>::value,
|
||||
"data type is neither move/copy constructible nor move/copy assignable");
|
||||
}
|
||||
}
|
||||
*ptr = std::move(_v);
|
||||
}
|
||||
|
||||
template <typename Tp>
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "generateJSON.hpp"
|
||||
#include "generateOTF2.hpp"
|
||||
#include "generatePerfetto.hpp"
|
||||
#include "generateStats.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "output_file.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "tmp_file.hpp"
|
||||
|
||||
#include "lib/common/environment.hpp"
|
||||
@@ -1335,7 +1337,7 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
"buffer tracing service for memory copy configure");
|
||||
}
|
||||
|
||||
if(tool::get_config().scratch_memory)
|
||||
if(tool::get_config().scratch_memory_trace)
|
||||
{
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
|
||||
buffer_size,
|
||||
@@ -1500,21 +1502,32 @@ api_registration_callback(rocprofiler_intercept_table_t,
|
||||
"Iterate rocporfiler agents")
|
||||
}
|
||||
|
||||
using stats_data_t = ::rocprofiler::tool::stats_data_t;
|
||||
using stats_data_t = ::rocprofiler::tool::stats_data_t;
|
||||
using stats_entry_t = ::rocprofiler::tool::stats_entry_t;
|
||||
using domain_stats_vec_t = ::rocprofiler::tool::domain_stats_vec_t;
|
||||
|
||||
template <typename Tp, domain_type DomainT>
|
||||
void
|
||||
generate_output(rocprofiler::tool::buffered_output<Tp, DomainT>& output_v,
|
||||
std::unordered_map<domain_type, stats_data_t>& contributions_v)
|
||||
domain_stats_vec_t& contributions_v)
|
||||
{
|
||||
if(!output_v) return;
|
||||
|
||||
output_v.read();
|
||||
|
||||
if(tool::get_config().stats || tool::get_config().summary_output)
|
||||
{
|
||||
output_v.stats = rocprofiler::tool::generate_stats(tool_functions, output_v.element_data);
|
||||
}
|
||||
|
||||
if(output_v.stats)
|
||||
{
|
||||
contributions_v.emplace_back(output_v.buffer_type_v, output_v.stats);
|
||||
}
|
||||
|
||||
if(tool::get_config().csv_output)
|
||||
{
|
||||
output_v.stats = rocprofiler::tool::generate_csv(tool_functions, output_v.element_data);
|
||||
contributions_v.emplace(output_v.buffer_type_v, output_v.stats);
|
||||
rocprofiler::tool::generate_csv(tool_functions, output_v.element_data, output_v.stats);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1543,7 +1556,7 @@ tool_fini(void* /*tool_data*/)
|
||||
auto counters_output =
|
||||
counter_collection_buffered_output_t{tool::get_config().counter_collection};
|
||||
auto scratch_memory_output =
|
||||
scratch_memory_buffered_output_t{tool::get_config().scratch_memory};
|
||||
scratch_memory_buffered_output_t{tool::get_config().scratch_memory_trace};
|
||||
|
||||
auto node_id_sort = [](const auto& lhs, const auto& rhs) { return lhs.node_id < rhs.node_id; };
|
||||
|
||||
@@ -1561,7 +1574,7 @@ tool_fini(void* /*tool_data*/)
|
||||
rocprofiler::tool::generate_csv(tool_functions, _agents);
|
||||
}
|
||||
|
||||
auto contributions = std::unordered_map<domain_type, stats_data_t>{};
|
||||
auto contributions = domain_stats_vec_t{};
|
||||
|
||||
generate_output(kernel_dispatch_output, contributions);
|
||||
generate_output(hsa_output, contributions);
|
||||
@@ -1580,6 +1593,7 @@ tool_fini(void* /*tool_data*/)
|
||||
{
|
||||
rocprofiler::tool::write_json(tool_functions,
|
||||
getpid(),
|
||||
contributions,
|
||||
_agents,
|
||||
_counters,
|
||||
&hip_output.element_data,
|
||||
@@ -1617,6 +1631,11 @@ tool_fini(void* /*tool_data*/)
|
||||
&scratch_memory_output.element_data);
|
||||
}
|
||||
|
||||
if(tool::get_config().summary_output)
|
||||
{
|
||||
rocprofiler::tool::generate_stats(tool_functions, contributions);
|
||||
}
|
||||
|
||||
auto destroy_output = [](auto& _buffered_output_v) { _buffered_output_v.destroy(); };
|
||||
|
||||
destroy_output(kernel_dispatch_output);
|
||||
|
||||
@@ -72,7 +72,7 @@ struct async_copy_info;
|
||||
struct async_copy_info<ROCPROFILER_MEMORY_COPY_##DIRECTION> \
|
||||
{ \
|
||||
static constexpr auto operation_idx = ROCPROFILER_MEMORY_COPY_##DIRECTION; \
|
||||
static constexpr auto name = #DIRECTION; \
|
||||
static constexpr auto name = "MEMORY_COPY_" #DIRECTION; \
|
||||
};
|
||||
|
||||
SPECIALIZE_ASYNC_COPY_INFO(NONE)
|
||||
|
||||
Odkázat v novém úkolu
Zablokovat Uživatele