Cleanup and reorg of lib/common (#34)

* Cleanup and reorg of lib/common

- remove stale code in helper.cpp
- move helper.hpp to demangle.hpp
- move helper.cpp to demangle.cpp
- update CMakeLists.txt with new filenames
- fix includes in config.cpp

* Remove log.hpp and join.hpp

- replace with glog and fmt

* Update lib/common/environment

- move implementation functions into cpp file

* Common library tests

- tests for demangling
- tests for mpl (template metaprogramming)
- tests for environment

[ROCm/rocprofiler-sdk commit: ba0eb11e96]
This commit is contained in:
Jonathan R. Madsen
2023-08-30 22:31:36 -05:00
zatwierdzone przez GitHub
rodzic 697c751c62
commit 144d7018e7
13 zmienionych plików z 474 dodań i 694 usunięć
@@ -1,9 +1,8 @@
#
# Builds common utilities into a static library
#
set(common_sources config.cpp helper.cpp)
set(common_headers config.hpp defines.hpp environment.hpp join.hpp log.hpp helper.hpp
mpl.hpp)
set(common_sources config.cpp environment.cpp demangle.cpp)
set(common_headers config.hpp defines.hpp environment.hpp demangle.hpp mpl.hpp)
add_library(rocprofiler-common-library STATIC)
add_library(rocprofiler::rocprofiler-common-library ALIAS rocprofiler-common-library)
@@ -20,10 +20,10 @@
//
#include "lib/common/config.hpp"
#include "lib/common/demangle.hpp"
#include "lib/common/environment.hpp"
#include "lib/common/helper.hpp"
#include "lib/common/join.hpp"
#include "lib/common/log.hpp"
#include <fmt/core.h>
#include <unistd.h>
#include <algorithm>
@@ -210,13 +210,13 @@ output_keys(std::string _tag)
auto _mpi_size = get_env<int>("OMPI_COMM_WORLD_SIZE", get_env<int>("MV2_COMM_WORLD_SIZE", 0));
auto _mpi_rank = get_env<int>("OMPI_COMM_WORLD_RANK", get_env<int>("MV2_COMM_WORLD_RANK", -1));
auto _dmp_size = join("", (_mpi_size) > 0 ? _mpi_size : 1);
auto _dmp_rank = join("", (_mpi_rank) > 0 ? _mpi_rank : 0);
auto _proc_id = join("", getpid());
auto _parent_id = join("", getppid());
auto _pgroup_id = join("", getpgid(getpid()));
auto _session_id = join("", getsid(getpid()));
auto _proc_size = join("", get_num_siblings());
auto _dmp_size = fmt::format("{}", (_mpi_size) > 0 ? _mpi_size : 1);
auto _dmp_rank = fmt::format("{}", (_mpi_rank) > 0 ? _mpi_rank : 0);
auto _proc_id = fmt::format("{}", getpid());
auto _parent_id = fmt::format("{}", getppid());
auto _pgroup_id = fmt::format("{}", getpgid(getpid()));
auto _session_id = fmt::format("{}", getsid(getpid()));
auto _proc_size = fmt::format("{}", get_num_siblings());
auto _pwd_string = get_env<std::string>("PWD", ".");
auto _slurm_job_id = get_env<std::string>("SLURM_JOB_ID", "0");
auto _slurm_proc_id = get_env("SLURM_PROCID", _dmp_rank);
@@ -248,7 +248,7 @@ output_keys(std::string _tag)
for(size_t i = 0; i < _cmdline.size(); ++i)
{
auto _v = _cmdline.at(i);
_options.emplace_back(join("", "%arg", i, "%"), _v, join("", "Argument #", i));
_options.emplace_back(fmt::format("%arg{}%", i), _v, fmt::format("Argument #{}", i));
}
}
@@ -317,19 +317,13 @@ format(std::string _fpath, const std::string& _tag)
}
auto _beg = std::regex_replace(_fpath, _re, "$1");
auto _end = std::regex_replace(_fpath, _re, "$4");
_fpath = join("", _beg, _val, _end);
_fpath = fmt::format("{}{}{}", _beg, _val, _end);
}
}
} catch(std::exception& _e)
{
fprintf(stderr,
"%s[rocprofiler][%s:%i] %s threw exception :: %s\n%s",
log::color::dmesg(),
__FILE__,
__LINE__,
__FUNCTION__,
_e.what(),
log::color::end());
LOG(WARNING) << "[rocprofiler] " << __FUNCTION__ << " threw an exception :: " << _e.what()
<< "\n";
}
// remove %arg<N>% where N >= argc
@@ -340,14 +334,8 @@ format(std::string _fpath, const std::string& _tag)
_fpath = std::regex_replace(_fpath, _re, "$1$4");
} catch(std::exception& _e)
{
fprintf(stderr,
"%s[rocprofiler][%s:%i] %s threw exception :: %s\n%s",
log::color::dmesg(),
__FILE__,
__LINE__,
__FUNCTION__,
_e.what(),
log::color::end());
LOG(WARNING) << "[rocprofiler] " << __FUNCTION__ << " threw an exception :: " << _e.what()
<< "\n";
}
return _fpath;
@@ -365,11 +353,11 @@ compose_filename(const config& _cfg)
{
if(_cfg.mpi_rank >= 0)
{
_output_file = join('.', _output_file, _cfg.mpi_rank);
_output_file = fmt::format("{}.{}", _output_file, _cfg.mpi_rank);
}
else
{
_output_file = join('.', _output_file, getpid());
_output_file = fmt::format("{}.{}", _output_file, getpid());
}
}
if(!_output_ext.empty())
@@ -18,7 +18,7 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
#include "lib/common/helper.hpp"
#include "lib/common/demangle.hpp"
#include <amd_comgr/amd_comgr.h>
@@ -32,11 +32,6 @@
#include <sstream>
#include <string>
#define ENABLE_BACKTRACE
#if defined(ENABLE_BACKTRACE)
# include <backtrace.h>
#endif
#define amd_comgr_(call) \
do \
{ \
@@ -127,79 +122,39 @@ cxa_demangle(std::string_view _mangled_name, int* _status)
return _demangled_name;
}
namespace
// C++ symbol demangle
std::string
cxx_demangle(std::string_view symbol)
{
#if defined(ENABLE_BACKTRACE)
int _status = 0;
auto demangled_str = cxa_demangle(symbol, &_status);
if(_status == 0)
{
return demangled_str;
}
// struct BackTraceInfo
// {
// struct ::backtrace_state* state = nullptr;
// std::stringstream sstream{};
// int depth = 0;
// int error = 0;
// };
amd_comgr_data_t mangled_data;
amd_comgr_(create_data(AMD_COMGR_DATA_KIND_BYTES, &mangled_data));
amd_comgr_(set_data(mangled_data, symbol.size(), symbol.data()));
// void
// errorCallback(void* data, const char* message, int errnum)
// {
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
// info->sstream << "ROCProfiler: error: " << message << '(' << errnum << ')';
// info->error = 1;
// }
amd_comgr_data_t demangled_data;
amd_comgr_(demangle_symbol_name(mangled_data, &demangled_data));
// void
// syminfoCallback(void* data,
// uintptr_t /* pc */,
// const char* symname,
// uintptr_t /* symval */,
// uintptr_t /* symsize */)
// {
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
size_t demangled_size = 0;
amd_comgr_(get_data(demangled_data, &demangled_size, nullptr));
// if(symname == nullptr) return;
demangled_str.resize(demangled_size);
amd_comgr_(get_data(demangled_data, &demangled_size, demangled_str.data()));
// int status = 0;
// auto&& _demangled = cxa_demangle(symname, &status);
// info->sstream << ' '
// << (status == 0 ? std::string_view{_demangled} : std::string_view{symname});
// }
amd_comgr_(release_data(mangled_data));
amd_comgr_(release_data(demangled_data));
return demangled_str;
}
// int
// fullCallback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function)
// {
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
// info->sstream << std::endl
// << " #" << std::dec << info->depth++ << ' ' << "0x" << std::noshowbase
// << std::hex << std::setfill('0') << std::setw(sizeof(pc) * 2) << pc;
// if(function == nullptr)
// {
// backtrace_syminfo(info->state, pc, syminfoCallback, errorCallback, data);
// }
// else
// {
// int status = 0;
// auto&& _demangled = cxa_demangle(function, &status);
// info->sstream << ' '
// << (status == 0 ? std::string_view{_demangled} :
// std::string_view{function});
// if(filename != nullptr)
// {
// info->sstream << " in " << filename;
// if(lineno != 0) info->sstream << ':' << std::dec << lineno;
// }
// }
// return info->error;
// }
#endif // defined (ENABLE_BACKTRACE)
} // namespace
/* The function extracts the kernel name from
input string. By using the iterators it finds the
window in the string which contains only the kernel name.
For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'*/
// The function extracts the kernel name from
// input string. By using the iterators it finds the
// window in the string which contains only the kernel name.
// For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'
std::string
truncate_name(std::string_view name)
{
@@ -245,129 +200,5 @@ truncate_name(std::string_view name)
rit++;
return std::string{name.substr(rend - rit, rit - rbeg)};
}
// C++ symbol demangle
std::string
cxx_demangle(std::string_view symbol)
{
int _status = 0;
auto demangled_str = cxa_demangle(symbol, &_status);
if(_status == 0)
{
return demangled_str;
}
amd_comgr_data_t mangled_data;
amd_comgr_(create_data(AMD_COMGR_DATA_KIND_BYTES, &mangled_data));
amd_comgr_(set_data(mangled_data, symbol.size(), symbol.data()));
amd_comgr_data_t demangled_data;
amd_comgr_(demangle_symbol_name(mangled_data, &demangled_data));
size_t demangled_size = 0;
amd_comgr_(get_data(demangled_data, &demangled_size, nullptr));
demangled_str.resize(demangled_size);
amd_comgr_(get_data(demangled_data, &demangled_size, demangled_str.data()));
amd_comgr_(release_data(mangled_data));
amd_comgr_(release_data(demangled_data));
return demangled_str;
}
// check if string has special char
bool
has_special_char(std::string_view str)
{
return std::find_if(str.begin(), str.end(), [](unsigned char ch) {
return !((isalnum(ch) != 0) || ch == '_' || ch == ':' || ch == ' ');
}) != str.end();
}
// check if string has correct counter format
bool
has_counter_format(std::string_view str)
{
return std::find_if(str.begin(), str.end(), [](unsigned char ch) {
return ((isalnum(ch) != 0) || ch == '_');
}) != str.end();
}
// trims the begining of the line for spaces
std::string
left_trim(std::string_view s)
{
constexpr std::string_view WHITESPACE = " \n\r\t\f\v";
size_t start = s.find_first_not_of(WHITESPACE);
if(start == std::string_view::npos) return std::string{};
return std::string{s.substr(start)};
}
// trims begining and end of input line in place
void
trim(std::string& str)
{
// Remove leading spaces.
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](unsigned char ch) {
return std::isspace(ch) == 0;
}));
// Remove trailing spaces.
str.erase(std::find_if(
str.rbegin(), str.rend(), [](unsigned char ch) { return std::isspace(ch) == 0; })
.base(),
str.end());
}
// replace unsuported specail chars with space
static void
handle_special_chars(std::string& str)
{
std::set<char> specialChars = {'!', '@', '#', '$', '%', '&', '(', ')', ',',
'*', '+', '-', '.', '/', ';', '<', '=', '>',
'?', '@', '{', '}', '^', '`', '~', '|', ':'};
// Iterate over the string and replace any special characters with a space.
for(char& i : str)
{
if(specialChars.find(i) != specialChars.end())
{
i = ' ';
}
}
}
// validate input coutners and correct format if needed
void
validate_counters_format(std::vector<std::string>& counters, std::string line)
{
// trim line for any white spaces
trim(line);
if(!(line[0] == '#' || line.find("pmc") == std::string::npos))
{
handle_special_chars(line);
std::stringstream input_line(line);
std::string counter;
while(getline(input_line, counter, ' '))
{
if(counter.substr(0, 3) != "pmc" && has_counter_format(counter))
{
counters.push_back(counter);
}
}
}
// raise exception with correct usage if user still managed to corrupt input
for(const auto& itr : counters)
{
if(!has_counter_format(itr))
{
fprintf(stderr,
"[rocprofiler] Bad input metric. usage --> pmc: <counter1> <counter2>\n");
}
}
}
} // namespace common
} // namespace rocprofiler
@@ -37,32 +37,15 @@ namespace common
[[nodiscard]] std::string
cxa_demangle(std::string_view _mangled_name, int* _status) __attribute__((nonnull(2)));
/* The function extracts the kernel name from
input string. By using the iterators it finds the
window in the string which contains only the kernel name.
For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'*/
std::string
truncate_name(std::string_view name);
// C++ symbol demangle
std::string
cxx_demangle(std::string_view symbol);
// check if string has special char
bool
has_special_char(std::string_view str);
// check if string has correct counter format
bool
has_counter_format(std::string_view str);
// trims the begining of the line for spaces
// The function extracts the kernel name from
// input string. By using the iterators it finds the
// window in the string which contains only the kernel name.
// For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'
std::string
left_trim(std::string_view s);
// validates pmc user input format
void
validate_counters_format(std::vector<std::string>& counters, std::string line);
truncate_name(std::string_view name);
} // namespace common
} // namespace rocprofiler
@@ -0,0 +1,102 @@
// Copyright (c) 2023 Advanced Micro Devices, Inc.
//
// 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 "lib/common/environment.hpp"
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <string_view>
namespace rocprofiler
{
namespace common
{
namespace impl
{
std::string
get_env(std::string_view env_id, std::string_view _default)
{
if(env_id.empty()) return std::string{_default};
char* env_var = ::std::getenv(env_id.data());
if(env_var) return std::string{env_var};
return std::string{_default};
}
std::string
get_env(std::string_view env_id, const char* _default)
{
return get_env(env_id, std::string_view{_default});
}
int
get_env(std::string_view env_id, int _default)
{
if(env_id.empty()) return _default;
char* env_var = ::std::getenv(env_id.data());
if(env_var)
{
try
{
return std::stoi(env_var);
} catch(std::exception& _e)
{
LOG(WARNING) << "[rocprofiler][get_env] Exception thrown converting getenv(\"" << env_id
<< "\") = " << env_var << " to integer :: " << _e.what()
<< ". Using default value of " << _default << "\n";
}
return _default;
}
return _default;
}
bool
get_env(std::string_view env_id, bool _default)
{
if(env_id.empty()) return _default;
char* env_var = ::std::getenv(env_id.data());
if(env_var)
{
if(std::string_view{env_var}.empty())
{
throw std::runtime_error(std::string{"No boolean value provided for "} +
std::string{env_id});
}
if(std::string_view{env_var}.find_first_not_of("0123456789") == std::string_view::npos)
{
return static_cast<bool>(std::stoi(env_var));
}
for(size_t i = 0; i < std::string_view{env_var}.length(); ++i)
env_var[i] = tolower(env_var[i]);
for(const auto& itr : {"off", "false", "no", "n", "f", "0"})
if(std::string_view{env_var} == itr) return false;
return true;
}
return _default;
}
} // namespace impl
} // namespace common
} // namespace rocprofiler
@@ -20,133 +20,30 @@
#pragma once
#include "lib/common/log.hpp"
#include <glog/logging.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#if !defined(ROCPROFILER_ENVIRON_LOG_NAME)
# if defined(ROCPROFILER_COMMON_LIBRARY_NAME)
# define ROCPROFILER_ENVIRON_LOG_NAME "[" ROCPROFILER_COMMON_LIBRARY_NAME "]"
# else
# define ROCPROFILER_ENVIRON_LOG_NAME "[environ]"
# endif
#endif
#if !defined(ROCPROFILER_ENVIRON_LOG_START)
# if defined(ROCPROFILER_COMMON_LIBRARY_LOG_START)
# define ROCPROFILER_ENVIRON_LOG_START ROCPROFILER_COMMON_LIBRARY_LOG_START
# elif defined(ROCPROFILER_LOG_COLORS_AVAILABLE)
# define ROCPROFILER_ENVIRON_LOG_START \
fprintf(stderr, "%s", ::rocprofiler::common::log::color::dmesg());
# else
# define ROCPROFILER_ENVIRON_LOG_START
# endif
#endif
#if !defined(ROCPROFILER_ENVIRON_LOG_END)
# if defined(ROCPROFILER_COMMON_LIBRARY_LOG_END)
# define ROCPROFILER_ENVIRON_LOG_END ROCPROFILER_COMMON_LIBRARY_LOG_END
# elif defined(ROCPROFILER_LOG_COLORS_AVAILABLE)
# define ROCPROFILER_ENVIRON_LOG_END \
fprintf(stderr, "%s", ::rocprofiler::common::log::color::dmesg());
# else
# define ROCPROFILER_ENVIRON_LOG_END
# endif
#endif
#define ROCPROFILER_ENVIRON_LOG(CONDITION, ...) \
if(CONDITION) \
{ \
fflush(stderr); \
ROCPROFILER_ENVIRON_LOG_START \
fprintf(stderr, "[rocprofiler]" ROCPROFILER_ENVIRON_LOG_NAME "[%i] ", getpid()); \
fprintf(stderr, __VA_ARGS__); \
ROCPROFILER_ENVIRON_LOG_END \
fflush(stderr); \
}
namespace rocprofiler
{
namespace common
{
namespace
namespace impl
{
inline std::string
get_env_impl(std::string_view env_id, std::string_view _default)
{
if(env_id.empty()) return std::string{_default};
char* env_var = ::std::getenv(env_id.data());
if(env_var) return std::string{env_var};
return std::string{_default};
}
std::string get_env(std::string_view, std::string_view);
inline std::string
get_env_impl(std::string_view env_id, const char* _default)
{
return get_env_impl(env_id, std::string_view{_default});
}
std::string
get_env(std::string_view, const char*);
inline int
get_env_impl(std::string_view env_id, int _default)
{
if(env_id.empty()) return _default;
char* env_var = ::std::getenv(env_id.data());
if(env_var)
{
try
{
return std::stoi(env_var);
} catch(std::exception& _e)
{
fprintf(stderr,
"[rocprofiler][get_env] Exception thrown converting getenv(\"%s\") = "
"%s to integer :: %s. Using default value of %i\n",
env_id.data(),
env_var,
_e.what(),
_default);
}
return _default;
}
return _default;
}
int
get_env(std::string_view, int);
inline bool
get_env_impl(std::string_view env_id, bool _default)
{
if(env_id.empty()) return _default;
char* env_var = ::std::getenv(env_id.data());
if(env_var)
{
if(std::string_view{env_var}.empty())
{
throw std::runtime_error(std::string{"No boolean value provided for "} +
std::string{env_id});
}
if(std::string_view{env_var}.find_first_not_of("0123456789") == std::string_view::npos)
{
return static_cast<bool>(std::stoi(env_var));
}
for(size_t i = 0; i < strlen(env_var); ++i)
env_var[i] = tolower(env_var[i]);
for(const auto& itr : {"off", "false", "no", "n", "f", "0"})
if(strcmp(env_var, itr) == 0) return false;
return true;
}
return _default;
}
} // namespace
bool
get_env(std::string_view, bool);
} // namespace impl
template <typename Tp>
inline auto
@@ -156,11 +53,11 @@ get_env(std::string_view env_id, Tp&& _default)
{
using Up = std::underlying_type_t<Tp>;
// cast to underlying type -> get_env -> cast to enum type
return static_cast<Tp>(get_env_impl(env_id, static_cast<Up>(_default)));
return static_cast<Tp>(impl::get_env(env_id, static_cast<Up>(_default)));
}
else
{
return get_env_impl(env_id, std::forward<Tp>(_default));
return impl::get_env(env_id, std::forward<Tp>(_default));
}
}
@@ -168,17 +65,14 @@ struct env_config
{
std::string env_name = {};
std::string env_value = {};
int override = 0;
int overwrite = 0;
auto operator()(bool _verbose = false) const
{
if(env_name.empty()) return -1;
ROCPROFILER_ENVIRON_LOG(_verbose,
"setenv(\"%s\", \"%s\", %i)\n",
env_name.c_str(),
env_value.c_str(),
override);
return setenv(env_name.c_str(), env_value.c_str(), override);
LOG_IF(INFO, _verbose) << "[rocprofiler][set_env] setenv(\"" << env_name << "\", \""
<< env_value << "\", " << overwrite << ")\n";
return setenv(env_name.c_str(), env_value.c_str(), overwrite);
}
};
} // namespace common
@@ -1,183 +0,0 @@
// Copyright (c) 2023 Advanced Micro Devices, Inc.
//
// 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 <array>
#include <initializer_list>
#include <ios>
#include <sstream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#if !defined(ROCPROFILER_FOLD_EXPRESSION)
# define ROCPROFILER_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
#endif
namespace rocprofiler
{
namespace common
{
namespace
{
template <typename Tp>
struct is_string_impl : std::false_type
{};
template <>
struct is_string_impl<std::string> : std::true_type
{};
template <>
struct is_string_impl<std::string_view> : std::true_type
{};
template <>
struct is_string_impl<const char*> : std::true_type
{};
template <>
struct is_string_impl<char*> : std::true_type
{};
template <typename Tp>
struct is_string : is_string_impl<std::remove_cv_t<std::decay_t<Tp>>>
{};
template <typename ArgT>
auto
as_string(ArgT&& _v, std::enable_if_t<is_string<ArgT>::value, int> = 0)
{
if constexpr(std::is_pointer<std::decay_t<ArgT>>::value)
{
return (_v == nullptr) ? std::string{"\"\""} : (std::string{"\""} + _v + std::string{"\""});
}
else
{
return std::string{"\""} + _v + std::string{"\""};
}
}
template <typename ArgT>
auto
as_string(ArgT&& _v, std::enable_if_t<!is_string<ArgT>::value, long> = 0)
{
return _v;
}
template <typename DelimT, typename... Args>
auto
join(DelimT&& _delim, Args&&... _args)
{
using delim_type = std::remove_cv_t<std::remove_reference_t<DelimT>>;
std::stringstream _ss{};
_ss << std::boolalpha;
if constexpr(std::is_same<delim_type, char>::value)
{
const char _delim_c[2] = {_delim, '\0'};
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim_c << _args);
auto _ret = _ss.str();
return (_ret.length() > 1) ? _ret.substr(1) : std::string{};
}
else
{
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim << _args);
auto _ret = _ss.str();
auto&& _len = std::string{_delim}.length();
return (_ret.length() > _len) ? _ret.substr(_len) : std::string{};
}
}
struct QuoteStrings
{};
template <typename DelimT, typename... Args>
auto
join(QuoteStrings&&, DelimT&& _delim, Args&&... _args)
{
using delim_type = std::remove_cv_t<std::remove_reference_t<DelimT>>;
std::stringstream _ss{};
_ss << std::boolalpha;
if constexpr(std::is_same<delim_type, char>::value)
{
const char _delim_c[2] = {_delim, '\0'};
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim_c << as_string(_args));
auto _ret = _ss.str();
return (_ret.length() > 1) ? _ret.substr(1) : std::string{};
}
else
{
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim << as_string(_args));
auto _ret = _ss.str();
auto&& _len = std::string{_delim}.length();
return (_ret.length() > _len) ? _ret.substr(_len) : std::string{};
}
}
template <typename... Args>
auto
join(std::array<std::string_view, 3>&& _delim, Args&&... _args)
{
return join("",
std::get<0>(_delim),
join(std::get<1>(_delim), std::forward<Args>(_args)...),
std::get<2>(_delim));
}
template <typename... Args>
auto
join(QuoteStrings&&, std::array<std::string_view, 3>&& _delim, Args&&... _args)
{
return join(QuoteStrings{},
"",
std::get<0>(_delim),
join(std::get<1>(_delim), std::forward<Args>(_args)...),
std::get<2>(_delim));
}
template <typename DelimB, typename DelimT, typename DelimE, typename... Args>
auto
join(std::tuple<DelimB, DelimT, DelimE>&& _delim, Args&&... _args)
{
return join("",
std::get<0>(_delim),
join(std::get<1>(_delim), std::forward<Args>(_args)...),
std::get<2>(_delim));
}
template <typename DelimB, typename DelimT, typename DelimE, typename... Args>
auto
join(QuoteStrings&&, std::tuple<DelimB, DelimT, DelimE>&& _delim, Args&&... _args)
{
return join(QuoteStrings{},
"",
std::get<0>(_delim),
join(std::get<1>(_delim), std::forward<Args>(_args)...),
std::get<2>(_delim));
}
} // namespace
} // namespace common
} // namespace rocprofiler
@@ -1,138 +0,0 @@
// MIT License
//
// Copyright (c) 2023 ROCm Developer Tools
//
// 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
#ifndef ROCPROFILER_LOG_COLORS_AVAILABLE
# define ROCPROFILER_LOG_COLORS_AVAILABLE 1
#endif
#include <cstdlib>
#include <cstring>
#include <string>
namespace rocprofiler
{
namespace common
{
namespace log
{
bool&
monochrome();
inline bool&
monochrome()
{
static bool _v = []() {
auto _val = false;
const char* _env_cstr = nullptr;
#if defined(ROCPROFILER_LOG_COLORS_ENV)
_env_cstr = std::getenv(ROCPROFILER_LOG_COLORS_ENV);
#elif defined(ROCPROFILER_PROJECT_NAME)
auto _env_name = std::string{ROCPROFILER_PROJECT_NAME} + "_MONOCHROME";
for(auto& itr : _env_name)
itr = toupper(itr);
_env_cstr = std::getenv(_env_name.c_str());
#else
_env_cstr = std::getenv("ROCPROFILER_MONOCHROME");
#endif
if(!_env_cstr) _env_cstr = std::getenv("MONOCHROME");
if(_env_cstr)
{
auto _env = std::string{_env_cstr};
// check if numeric
if(_env.find_first_not_of("0123456789") == std::string::npos)
{
return _env.length() > 1 || _env[0] != '0';
}
for(auto& itr : _env)
itr = tolower(itr);
// check for matches to acceptable forms of false
for(const auto& itr : {"off", "false", "no", "n", "f"})
{
if(_env == itr) return false;
}
// check for matches to acceptable forms of true
for(const auto& itr : {"on", "true", "yes", "y", "t"})
{
if(_env == itr) return true;
}
}
return _val;
}();
return _v;
}
namespace color
{
static constexpr auto info_value = "\033[01;34m";
static constexpr auto warning_value = "\033[01;33m";
static constexpr auto fatal_value = "\033[01;31m";
static constexpr auto source_value = "\033[01;32m";
static constexpr auto dmesg_value = "\033[01;37m";
static constexpr auto end_value = "\033[0m";
inline const char*
info()
{
return (log::monochrome()) ? "" : info_value;
}
inline const char*
warning()
{
return (log::monochrome()) ? "" : warning_value;
}
inline const char*
fatal()
{
return (log::monochrome()) ? "" : fatal_value;
}
inline const char*
source()
{
return (log::monochrome()) ? "" : source_value;
}
inline const char*
dmesg()
{
return (log::monochrome()) ? "" : dmesg_value;
}
inline const char*
end()
{
return (log::monochrome()) ? "" : end_value;
}
} // namespace color
} // namespace log
} // namespace common
} // namespace rocprofiler
@@ -2,3 +2,4 @@
#
#
add_subdirectory(buffering)
add_subdirectory(common)
@@ -0,0 +1,23 @@
#
# Tests for the common library
#
project(rocprofiler-tests-common LANGUAGES C CXX)
include(GoogleTest)
set(common_sources demangling.cpp environment.cpp mpl.cpp)
add_executable(common-tests)
target_sources(common-tests PRIVATE ${common_sources})
target_link_libraries(
common-tests
PRIVATE rocprofiler::rocprofiler-headers rocprofiler::rocprofiler-common-library
GTest::gtest GTest::gtest_main)
gtest_add_tests(
TARGET common-tests
SOURCES ${common_sources}
TEST_LIST common-tests_TESTS
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${common-tests_TESTS} PROPERTIES TIMEOUT 45 LABELS "unittests")
@@ -0,0 +1,95 @@
// MIT License
//
// Copyright (c) 2023 ROCm Developer Tools
//
// 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 "lib/common/demangle.hpp"
#include <gtest/gtest.h>
#include <string_view>
#include <utility>
TEST(common, demangling)
{
// the purpose of this test is to verify the cxx_demangle function.
// We want to make sure that the function produces the right demangling
// when it is a correctly mangled string and does not change the string
// when demangling fails
using strview_pair_t = std::pair<std::string_view, std::string_view>;
for(auto [mangled, demangled] :
{strview_pair_t{"_ZN11rocprofiler8internal18correlation_config20get_unique_record_idEv",
"rocprofiler::internal::correlation_config::get_unique_record_id()"},
strview_pair_t{"_ZN11rocprofiler8internal18get_active_configsEv",
"rocprofiler::internal::get_active_configs()"},
strview_pair_t{"_ZN11rocprofiler8internal22get_registered_configsEv",
"rocprofiler::internal::get_registered_configs()"},
strview_pair_t{
"_ZZN11rocprofiler8internal18correlation_config20get_unique_record_idEvE2_v",
"rocprofiler::internal::correlation_config::get_unique_record_id()::_v"},
strview_pair_t{"_ZZN11rocprofiler8internal18get_active_configsEvE2_v",
"rocprofiler::internal::get_active_configs()::_v"},
strview_pair_t{"_ZZN11rocprofiler8internal22get_registered_configsEvE2_v",
"rocprofiler::internal::get_registered_configs()::_v"}})
{
// verify the demangling works
EXPECT_EQ(rocprofiler::common::cxx_demangle(mangled), demangled)
<< "failed to demangle '" << mangled << "'";
// verify we get same string in when improperly mangled string
auto bad_mangled = std::string{"_Z"} + std::string{mangled};
EXPECT_EQ(rocprofiler::common::cxx_demangle(bad_mangled), bad_mangled)
<< "demangling succeeded for '" << bad_mangled << "'";
}
}
TEST(common, truncate)
{
// this test is verify that the truncate_name function correctly finds the function
// name in a complex template instantiation
auto mangled = std::string_view{"_ZSt16__do_uninit_copyIPKSt4pairINSt7__cxx1112basic_"
"stringIcSt11char_traitsIcESaIcEEES6_EPS7_ET0_T_SC_SB_"};
auto untruncated = std::string_view{
"std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> "
">, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >* "
"std::__do_uninit_copy<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, "
"std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, "
"std::allocator<char> > > const*, std::pair<std::__cxx11::basic_string<char, "
"std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, "
"std::char_traits<char>, std::allocator<char> > "
">*>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, "
"std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, "
"std::allocator<char> > > const*, std::pair<std::__cxx11::basic_string<char, "
"std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, "
"std::char_traits<char>, std::allocator<char> > > const*, "
"std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> "
">, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >*)"};
EXPECT_EQ(rocprofiler::common::cxx_demangle(mangled), untruncated);
EXPECT_EQ(rocprofiler::common::truncate_name(untruncated),
std::string_view{"__do_uninit_copy"});
EXPECT_EQ(rocprofiler::common::truncate_name(rocprofiler::common::cxx_demangle(mangled)),
std::string_view{"__do_uninit_copy"});
}
@@ -0,0 +1,115 @@
// MIT License
//
// Copyright (c) 2023 ROCm Developer Tools
//
// 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 "lib/common/environment.hpp"
#include <gtest/gtest.h>
TEST(common, environment)
{
using rocprofiler::common::env_config;
using rocprofiler::common::get_env;
enum TestBareEnum : unsigned short // NOLINT(performance-enum-size)
{
BZero = 0,
BOne = 1,
};
enum class TestClassEnum : unsigned short // NOLINT(performance-enum-size)
{
CZero = 0,
COne = 1,
};
//
// int testing section
//
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_INT", 0), 0);
setenv("ROCPROFILER_ENV_TEST_INT", "1", 1);
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_INT", 0), 1);
env_config{"ROCPROFILER_ENV_TEST_INT", "2"}();
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_INT", 0), 1);
env_config{"ROCPROFILER_ENV_TEST_INT", "2", 1}();
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_INT", 0), 2);
//
// enum testing section
//
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_BARE_ENUM", BZero), BZero);
env_config{"ROCPROFILER_ENV_TEST_BARE_ENUM", "1", 1}();
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_BARE_ENUM", BZero), BOne);
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_CLASS_ENUM", TestClassEnum::CZero),
TestClassEnum::CZero);
env_config{"ROCPROFILER_ENV_TEST_CLASS_ENUM", "1", 1}();
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_CLASS_ENUM", TestClassEnum::CZero),
TestClassEnum::COne);
//
// string testing section
//
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_STR", "nostr"), std::string_view{"nostr"});
env_config{"ROCPROFILER_ENV_TEST_STR", "hasstr", 0}();
EXPECT_EQ(get_env("ROCPROFILER_ENV_TEST_STR", "nostr"), std::string_view{"hasstr"});
//
// bool testing section
//
EXPECT_FALSE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "YES", 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "yes", 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "y", 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "true", 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "on", 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "no", 1}();
EXPECT_FALSE(get_env("ROCPROFILER_ENV_TEST_BOOL", true));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "false", 1}();
EXPECT_FALSE(get_env("ROCPROFILER_ENV_TEST_BOOL", true));
env_config{"ROCPROFILER_ENV_TEST_BOOL", "0", 1}();
EXPECT_FALSE(get_env("ROCPROFILER_ENV_TEST_BOOL", true));
for(auto n : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
{
env_config{"ROCPROFILER_ENV_TEST_BOOL", std::to_string(n), 1}();
EXPECT_TRUE(get_env("ROCPROFILER_ENV_TEST_BOOL", false));
}
}
@@ -0,0 +1,70 @@
// MIT License
//
// Copyright (c) 2023 ROCm Developer Tools
//
// 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 "lib/common/mpl.hpp"
#include <gtest/gtest.h>
#include <tuple>
TEST(common, mpl)
{
namespace mpl = ::rocprofiler::common::mpl;
struct Foo;
using test_type_list_t = mpl::type_list<int, long, int, Foo, Foo*>;
using test_tuple_t = std::tuple<int, long, int, Foo, Foo*>;
EXPECT_EQ(mpl::size_of<test_type_list_t>::value, 5);
EXPECT_EQ(mpl::size_of<test_tuple_t>::value, 5);
{
constexpr bool _foo_p_is_one_of = mpl::is_one_of<Foo*, test_type_list_t>::value;
constexpr bool _int_is_one_of = mpl::is_one_of<int, test_type_list_t>::value;
constexpr bool _double_is_one_of = mpl::is_one_of<double, test_type_list_t>::value;
EXPECT_TRUE(_foo_p_is_one_of);
EXPECT_TRUE(_int_is_one_of);
EXPECT_FALSE(_double_is_one_of);
constexpr auto _foo_p_index_of = mpl::index_of<Foo*, test_type_list_t>::value;
constexpr auto _int_index_of = mpl::index_of<int, test_type_list_t>::value;
EXPECT_EQ(_foo_p_index_of, 4);
EXPECT_EQ(_int_index_of, 0);
}
{
constexpr bool _foo_p_is_one_of = mpl::is_one_of<Foo*, test_tuple_t>::value;
constexpr bool _int_is_one_of = mpl::is_one_of<int, test_tuple_t>::value;
constexpr bool _double_is_one_of = mpl::is_one_of<double, test_tuple_t>::value;
EXPECT_TRUE(_foo_p_is_one_of);
EXPECT_TRUE(_int_is_one_of);
EXPECT_FALSE(_double_is_one_of);
constexpr auto _foo_p_index_of = mpl::index_of<Foo*, test_tuple_t>::value;
constexpr auto _int_index_of = mpl::index_of<int, test_tuple_t>::value;
EXPECT_EQ(_foo_p_index_of, 4);
EXPECT_EQ(_int_index_of, 0);
}
}