CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
504 lines
18 KiB
C++
504 lines
18 KiB
C++
// Copyright (c) Advanced Micro Devices, Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "generate_config.hpp"
|
|
#include "common.hpp"
|
|
#include "defines.hpp"
|
|
#include "info_type.hpp"
|
|
|
|
#include "common/delimit.hpp"
|
|
#include "common/env_vars.hpp"
|
|
#include "common/environment.hpp"
|
|
#include "common/json_config.hpp"
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#include <spdlog/fmt/fmt.h>
|
|
#include <timemory/mpl/concepts.hpp>
|
|
#include <timemory/mpl/policy.hpp>
|
|
#include <timemory/settings.hpp>
|
|
#include <timemory/settings/types.hpp>
|
|
#include <timemory/tpls/cereal/archives.hpp>
|
|
#include <timemory/tpls/cereal/cereal.hpp>
|
|
#include <timemory/tpls/cereal/cereal/archives/json.hpp>
|
|
#include <timemory/tpls/cereal/cereal/archives/xml.hpp>
|
|
#include <timemory/tpls/cereal/cereal/cereal.hpp>
|
|
#include <timemory/utility/filepath.hpp>
|
|
#include <timemory/utility/types.hpp>
|
|
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace cereal = ::tim::cereal;
|
|
namespace filepath = ::tim::filepath;
|
|
using settings = ::tim::settings;
|
|
using ::tim::tsettings;
|
|
using ::tim::type_list;
|
|
using ::tim::policy::output_archive;
|
|
|
|
namespace
|
|
{
|
|
struct custom_setting_serializer
|
|
{
|
|
static std::array<bool, TOTAL> options;
|
|
static const format_options* fmt;
|
|
};
|
|
|
|
template <typename Tp>
|
|
bool
|
|
ignore_setting(const Tp& _v, const format_options& fmt_opts)
|
|
{
|
|
if(_v->get_hidden()) return true;
|
|
if(exclude_setting(_v->get_env_name())) return true;
|
|
if(_v->get_config_updated() || _v->get_environ_updated()) return false;
|
|
if(!is_selected(_v->get_env_name()) && !is_selected(_v->get_name())) return true;
|
|
if(fmt_opts.available_only && !_v->get_enabled()) return true;
|
|
if(!category_view.empty())
|
|
{
|
|
bool _found = false;
|
|
for(auto& category : _v->get_categories())
|
|
{
|
|
if(category_view.count(category) > 0 ||
|
|
category_view.count(fmt::format("settings::{}", category)) > 0)
|
|
{
|
|
_found = true;
|
|
break;
|
|
}
|
|
}
|
|
if(!_found) return true;
|
|
}
|
|
if(category_view.count("deprecated") == 0 &&
|
|
category_view.count("settings::deprecated") == 0 &&
|
|
_v->get_categories().count("deprecated") > 0)
|
|
return true;
|
|
if(!fmt_opts.print_advanced && category_view.count("advanced") == 0 &&
|
|
category_view.count("settings::advanced") == 0 &&
|
|
_v->get_categories().count("advanced") > 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
} // namespace
|
|
|
|
std::array<bool, TOTAL> custom_setting_serializer::options = { false };
|
|
const format_options* custom_setting_serializer::fmt = nullptr;
|
|
|
|
namespace tim
|
|
{
|
|
namespace operation
|
|
{
|
|
template <typename Tp>
|
|
struct setting_serialization<Tp, custom_setting_serializer>
|
|
{
|
|
template <typename ArchiveT>
|
|
void operator()(ArchiveT&, const char*, const Tp&) const
|
|
{}
|
|
|
|
template <typename ArchiveT>
|
|
void operator()(ArchiveT&, const char*, Tp&&) const
|
|
{}
|
|
};
|
|
//
|
|
template <typename Tp>
|
|
struct setting_serialization<tsettings<Tp>, custom_setting_serializer>
|
|
{
|
|
using value_type = tsettings<Tp>;
|
|
|
|
template <typename ArchiveT>
|
|
void operator()(ArchiveT& _ar, value_type& _val) const
|
|
{
|
|
static_assert(concepts::is_output_archive<ArchiveT>::value,
|
|
"Requires an output archive");
|
|
|
|
if(ignore_setting(&_val, *custom_setting_serializer::fmt)) return;
|
|
|
|
auto _save = std::shared_ptr<value_type>{};
|
|
if constexpr(concepts::is_string_type<Tp>::value)
|
|
{
|
|
if(_val.get_name() != "time_format")
|
|
_val.set(settings::format(_val.get(), settings::instance()->get_tag()));
|
|
if(_val.get_name() == "config_file")
|
|
{
|
|
_save = std::make_shared<value_type>(_val);
|
|
_val.set(Tp{});
|
|
}
|
|
}
|
|
|
|
if(custom_setting_serializer::fmt->all_info)
|
|
{
|
|
_ar(cereal::make_nvp(_val.get_env_name().c_str(), _val));
|
|
}
|
|
else
|
|
{
|
|
Tp _v = _val.get();
|
|
_ar.setNextName(_val.get_env_name().c_str());
|
|
_ar.startNode();
|
|
_ar(cereal::make_nvp("name", _val.get_name()));
|
|
_ar(cereal::make_nvp("value", _v));
|
|
if(custom_setting_serializer::options[DESC])
|
|
_ar(cereal::make_nvp("description", _val.get_description()));
|
|
if(custom_setting_serializer::options[CATEGORY])
|
|
_ar(cereal::make_nvp("description", _val.get_categories()));
|
|
if(custom_setting_serializer::options[VAL])
|
|
_ar(cereal::make_nvp("choices", _val.get_choices()));
|
|
_ar.finishNode();
|
|
}
|
|
|
|
if(_save) _val.set(_save->get());
|
|
}
|
|
};
|
|
} // namespace operation
|
|
} // namespace tim
|
|
|
|
template <typename... Tp>
|
|
void
|
|
push(type_list<Tp...>)
|
|
{
|
|
ROCPROFSYS_FOLD_EXPRESSION(
|
|
settings::push_serialize_map_callback<Tp, custom_setting_serializer>());
|
|
ROCPROFSYS_FOLD_EXPRESSION(
|
|
settings::push_serialize_data_callback<Tp, custom_setting_serializer>(
|
|
type_list<std::string>{}));
|
|
}
|
|
|
|
template <typename... Tp>
|
|
void
|
|
pop(type_list<Tp...>)
|
|
{
|
|
ROCPROFSYS_FOLD_EXPRESSION(
|
|
settings::pop_serialize_map_callback<Tp, custom_setting_serializer>());
|
|
ROCPROFSYS_FOLD_EXPRESSION(
|
|
settings::pop_serialize_data_callback<Tp, custom_setting_serializer>(
|
|
type_list<std::string>{}));
|
|
}
|
|
|
|
void
|
|
update_choices(const std::shared_ptr<settings>&);
|
|
|
|
void
|
|
generate_config(std::string _config_file, const std::set<std::string>& _config_fmts,
|
|
const std::array<bool, TOTAL>& _options, const format_options& fmt_opts)
|
|
{
|
|
custom_setting_serializer::options = _options;
|
|
custom_setting_serializer::fmt = &fmt_opts;
|
|
|
|
auto _settings = tim::settings::shared_instance();
|
|
tim::settings::push();
|
|
_settings->find("suppress_config")->second->reset();
|
|
_settings->find("suppress_parsing")->second->reset();
|
|
|
|
_config_file = settings::format(_config_file, _settings->get_tag());
|
|
bool _absolute = _config_file.at(0) == '/';
|
|
auto _dirs = rocprofsys::delimit(_config_file, "/\\/");
|
|
_config_file = _dirs.back();
|
|
_dirs.pop_back();
|
|
|
|
std::string _output_dir = ".";
|
|
if(!_dirs.empty() && !(_dirs.size() == 1 && _dirs.at(0) == "."))
|
|
{
|
|
_output_dir = std::string{ (_absolute) ? "/" : "" } + _dirs.front();
|
|
_dirs.erase(_dirs.begin());
|
|
for(const auto& dir : _dirs)
|
|
{
|
|
_output_dir += '/' + dir;
|
|
}
|
|
}
|
|
_output_dir += "/";
|
|
|
|
auto _fmts = std::set<std::string>{};
|
|
std::string _txt_ext = ".cfg";
|
|
for(std::string itr : { ".cfg", ".txt", ".json", ".xml" })
|
|
{
|
|
if(_config_file.length() <= itr.length()) continue;
|
|
auto _pos = _config_file.rfind(itr);
|
|
if(_pos == _config_file.length() - itr.length())
|
|
{
|
|
if(itr == ".cfg" || itr == ".txt") _txt_ext = itr;
|
|
_fmts.emplace(itr.substr(1));
|
|
_config_file = _config_file.substr(0, _pos);
|
|
}
|
|
}
|
|
|
|
if(_fmts.empty() && _config_fmts.size() == 1)
|
|
_fmts = _config_fmts;
|
|
else if(!_fmts.empty())
|
|
{
|
|
for(auto& itr : _config_fmts)
|
|
_fmts.emplace(itr);
|
|
}
|
|
|
|
update_choices(_settings);
|
|
|
|
using json_t = cereal::PrettyJSONOutputArchive;
|
|
using xml_t = cereal::XMLOutputArchive;
|
|
|
|
// stores the original serializer and replaces it with the custom one
|
|
push(type_list<json_t, xml_t>{});
|
|
|
|
static std::time_t _time{ std::time(nullptr) };
|
|
|
|
auto _serialize = [_settings](auto&& _ar) {
|
|
_ar->setNextName(TIMEMORY_PROJECT_NAME);
|
|
_ar->startNode();
|
|
(*_ar)(cereal::make_nvp("version", std::string{ ROCPROFSYS_VERSION_STRING }));
|
|
(*_ar)(cereal::make_nvp("date", tim::get_local_datetime("%F_%H.%M", &_time)));
|
|
settings::serialize_settings(*_ar, *_settings);
|
|
_ar->finishNode();
|
|
};
|
|
|
|
auto _nout = 0;
|
|
auto _open = [&_nout, &fmt_opts](std::ofstream& _ofs, const std::string& _fname,
|
|
const std::string& _type) -> std::ofstream& {
|
|
++_nout;
|
|
if(file_exists(_fname))
|
|
{
|
|
if(fmt_opts.force_config)
|
|
{
|
|
if(settings::verbose() >= 1)
|
|
std::cout << "[rocprof-sys-avail] File '" << _fname
|
|
<< "' exists. Overwrite force...\n";
|
|
}
|
|
else
|
|
{
|
|
std::cout << "[rocprof-sys-avail] File '" << _fname
|
|
<< "' exists. Overwrite? " << std::flush;
|
|
std::string _response = {};
|
|
std::cin >> _response;
|
|
if(!rocprofsys::to_bool(_response, false))
|
|
{
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(filepath::open(_ofs, _fname))
|
|
{
|
|
if(settings::verbose() >= 0)
|
|
printf("[rocprof-sys-avail] Outputting %s configuration file '%s'...\n",
|
|
_type.c_str(), _fname.c_str());
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error(
|
|
fmt::format("Error opening {} output file: {}", _type, _fname));
|
|
}
|
|
return _ofs;
|
|
};
|
|
|
|
if(_fmts.count("json") > 0)
|
|
{
|
|
// JSON schema output includes all ROCPROFSYS_* settings regardless of
|
|
// --filter, --categories, or --advanced flags. This is intentional: the
|
|
// schema has a fixed hierarchical structure and is designed for reuse
|
|
// with --preset, so partial exports would produce incomplete configs.
|
|
std::map<std::string, std::string> env_map;
|
|
for(const auto& itr : *_settings)
|
|
{
|
|
if(exclude_setting(itr.second->get_env_name())) continue;
|
|
if(itr.second->get_hidden()) continue;
|
|
|
|
const auto& env_name = itr.second->get_env_name();
|
|
if(env_name.find("ROCPROFSYS_") != 0) continue;
|
|
|
|
// Include all vars, even empty ones — the schema function
|
|
// handles empty values appropriately (e.g., empty string fields
|
|
// are still valid and indicate the setting exists).
|
|
env_map[env_name] = itr.second->as_string();
|
|
}
|
|
|
|
// Convert to hierarchical preset JSON schema (compatible with --preset)
|
|
auto preset_json = rocprofsys::json_config::env_vars_to_json_schema(env_map);
|
|
|
|
// Add metadata
|
|
auto preset_name = fmt_opts.preset_name;
|
|
if(preset_name.empty()) preset_name = _config_file;
|
|
preset_json["metadata"]["name"] = preset_name;
|
|
if(!fmt_opts.preset_description.empty())
|
|
preset_json["metadata"]["description"] = fmt_opts.preset_description;
|
|
|
|
auto _fname = settings::compose_output_filename(_config_file, ".json", false, -1,
|
|
true, _output_dir);
|
|
std::ofstream ofs{};
|
|
_open(ofs, _fname, "JSON") << preset_json.dump(4) << "\n";
|
|
}
|
|
|
|
if(_fmts.count("xml") > 0)
|
|
{
|
|
std::stringstream _ss{};
|
|
output_archive<cereal::XMLOutputArchive>::indent() = true;
|
|
_serialize(output_archive<cereal::XMLOutputArchive>::get(_ss));
|
|
auto _fname = settings::compose_output_filename(_config_file, ".xml", false, -1,
|
|
true, _output_dir);
|
|
std::ofstream ofs{};
|
|
_open(ofs, _fname, "XML") << _ss.str() << "\n";
|
|
}
|
|
|
|
if(_fmts.count("txt") > 0 || _fmts.count("cfg") > 0 || _nout == 0)
|
|
{
|
|
std::stringstream _ss{};
|
|
size_t _w = fmt_opts.min_width;
|
|
|
|
std::vector<std::shared_ptr<tim::vsettings>> _data{};
|
|
for(const auto& itr : *_settings)
|
|
{
|
|
if(exclude_setting(itr.second->get_env_name())) continue;
|
|
for(const auto& citr : itr.second->get_categories())
|
|
if(citr == "deprecated") continue;
|
|
if(ignore_setting(itr.second, fmt_opts)) continue;
|
|
_data.emplace_back(itr.second);
|
|
}
|
|
|
|
if(fmt_opts.alphabetical)
|
|
std::sort(_data.begin(), _data.end(), [](auto _lhs, auto _rhs) {
|
|
return _lhs->get_name() < _rhs->get_name();
|
|
});
|
|
else
|
|
{
|
|
_settings->ordering();
|
|
std::sort(_data.begin(), _data.end(), [](auto _lhs, auto _rhs) {
|
|
auto _lomni = _lhs->get_categories().count("rocprofsys") > 0;
|
|
auto _romni = _rhs->get_categories().count("rocprofsys") > 0;
|
|
if(_lomni && !_romni) return true;
|
|
if(_romni && !_lomni) return false;
|
|
namespace env_vars = rocprofsys::env_vars;
|
|
for(const auto* itr :
|
|
{ env_vars::CONFIG, env_vars::MODE, env_vars::TRACE,
|
|
env_vars::TRACE_LEGACY, env_vars::PROFILE, env_vars::USE_SAMPLING,
|
|
env_vars::USE_PROCESS_SAMPLING, env_vars::USE_AMD_SMI,
|
|
env_vars::USE_AINIC, env_vars::USE_KOKKOSP, env_vars::USE_OMPT,
|
|
"ROCPROFSYS_USE", env_vars::OUTPUT })
|
|
{
|
|
if(_lhs->get_env_name().find(itr) == 0 &&
|
|
_rhs->get_env_name().find(itr) != 0)
|
|
return true;
|
|
if(_rhs->get_env_name().find(itr) == 0 &&
|
|
_lhs->get_env_name().find(itr) != 0)
|
|
return false;
|
|
}
|
|
for(const auto* itr :
|
|
{ env_vars::SUPPRESS_PARSING, env_vars::SUPPRESS_CONFIG })
|
|
{
|
|
if(_lhs->get_env_name().find(itr) == 0 &&
|
|
_rhs->get_env_name().find(itr) != 0)
|
|
return false;
|
|
if(_rhs->get_env_name().find(itr) == 0 &&
|
|
_lhs->get_env_name().find(itr) != 0)
|
|
return true;
|
|
}
|
|
return _lhs->get_name() < _rhs->get_name();
|
|
});
|
|
}
|
|
|
|
for(const auto& itr : _data)
|
|
{
|
|
_w = std::max(_w, itr->get_env_name().length());
|
|
}
|
|
|
|
for(const auto& itr : _data)
|
|
{
|
|
if(exclude_setting(itr->get_env_name())) continue;
|
|
|
|
auto _has_info = (fmt_opts.all_info || _options[DESC] || _options[CATEGORY] ||
|
|
_options[VAL]);
|
|
|
|
if(_has_info) _ss << "\n# name:\n# " << itr->get_name() << "\n#\n";
|
|
|
|
if(_options[DESC] || fmt_opts.all_info)
|
|
{
|
|
_ss << "# description:\n";
|
|
auto _desc = rocprofsys::delimit(itr->get_description(), " \n");
|
|
std::stringstream _line{};
|
|
_line << "# ";
|
|
auto _write = [&_line, &_ss, _w](std::string_view _str) {
|
|
if(_line.str().length() + _str.length() + 1 >= _w)
|
|
{
|
|
_ss << _line.str() << "\n";
|
|
_line = std::stringstream{};
|
|
_line << "# ";
|
|
}
|
|
_line << " " << _str;
|
|
};
|
|
for(auto& iitr : _desc)
|
|
_write(iitr);
|
|
_ss << _line.str() << "\n#\n";
|
|
}
|
|
if(_options[CATEGORY] || fmt_opts.all_info)
|
|
{
|
|
_ss << "# categories:\n";
|
|
for(const auto& iitr : itr->get_categories())
|
|
_ss << "# " << iitr << "\n";
|
|
_ss << "#\n";
|
|
}
|
|
if((_options[VAL] || fmt_opts.all_info) && !itr->get_choices().empty())
|
|
{
|
|
auto _choices = itr->get_choices();
|
|
filter_operations(itr->get_env_name(), _choices);
|
|
|
|
if(!_choices.empty())
|
|
{
|
|
_ss << "# choices:\n";
|
|
for(const auto& iitr : _choices)
|
|
_ss << "# " << iitr << "\n";
|
|
_ss << "#\n";
|
|
}
|
|
}
|
|
if(_has_info) _ss << "\n";
|
|
_ss << std::left << std::setw(_w + 10) << itr->get_env_name() << " = ";
|
|
auto _v = itr->as_string();
|
|
if(itr->get_name() == "config_file") _v = {};
|
|
if(!_v.empty() && fmt_opts.expand_keys && itr->get_name() != "time_format")
|
|
_v = settings::format(_v, _settings->get_tag());
|
|
_ss << _v << "\n";
|
|
}
|
|
auto _fname = settings::compose_output_filename(_config_file, _txt_ext, false, -1,
|
|
true, _output_dir);
|
|
std::ofstream ofs{};
|
|
_open(ofs, _fname, "text")
|
|
<< "# auto-generated by rocprof-sys-avail (version "
|
|
<< ROCPROFSYS_VERSION_STRING << ") on "
|
|
<< tim::get_local_datetime("%F @ %H:%M", &_time) << "\n\n"
|
|
<< _ss.str();
|
|
}
|
|
|
|
// restores the original serializer
|
|
pop(type_list<json_t, xml_t>{});
|
|
|
|
tim::settings::pop();
|
|
}
|
|
|
|
void
|
|
update_choices(const std::shared_ptr<settings>& _settings)
|
|
{
|
|
std::vector<info_type> _info = get_component_info<TIMEMORY_NATIVE_COMPONENTS_END>();
|
|
|
|
if(_settings->get_verbose() >= 2 || _settings->get_debug())
|
|
printf("[rocprof-sys-avail] # of component found: %zu\n", _info.size());
|
|
|
|
_info.erase(std::remove_if(_info.begin(), _info.end(),
|
|
[](const auto& itr) {
|
|
if(!itr.is_available()) return true;
|
|
// NOLINTNEXTLINE
|
|
for(const auto& nitr :
|
|
{ "cuda", "cupti", "nvtx", "roofline", "_bundle",
|
|
"data_integer", "data_unsigned", "data_floating",
|
|
"printer" })
|
|
{
|
|
if(itr.name().find(nitr) != std::string::npos)
|
|
return true;
|
|
}
|
|
return false;
|
|
}),
|
|
_info.end());
|
|
|
|
std::vector<std::string> _component_choices = {};
|
|
_component_choices.reserve(_info.size());
|
|
for(const auto& itr : _info)
|
|
_component_choices.emplace_back(itr.id_type());
|
|
if(_settings->get_verbose() >= 2 || _settings->get_debug())
|
|
printf("[rocprof-sys-avail] # of component choices: %zu\n",
|
|
_component_choices.size());
|
|
_settings->find(std::string{ rocprofsys::env_vars::TIMEMORY_COMPONENTS })
|
|
->second->set_choices(_component_choices);
|
|
}
|