9ef3800986
- complete with ctest support
410 строки
11 KiB
C++
410 строки
11 KiB
C++
// MIT License
|
|
//
|
|
// Copyright (c) 2020, The Regents of the University of California,
|
|
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
|
// required approvals from the U.S. Dept. of Energy). 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.
|
|
|
|
#ifndef TIMEMORY_UTILITY_UTILITY_CPP_
|
|
#define TIMEMORY_UTILITY_UTILITY_CPP_ 1
|
|
|
|
#include "timemory/macros/os.hpp"
|
|
#include "timemory/utility/macros.hpp"
|
|
|
|
#if !defined(TIMEMORY_UTILITY_HEADER_MODE)
|
|
# include "timemory/utility/utility.hpp"
|
|
#endif
|
|
|
|
namespace tim
|
|
{
|
|
//
|
|
std::string
|
|
dirname(std::string _fname)
|
|
{
|
|
#if defined(TIMEMORY_UNIX)
|
|
char* _cfname = realpath(_fname.c_str(), nullptr);
|
|
_fname = std::string(_cfname);
|
|
free(_cfname);
|
|
|
|
while(_fname.find("\\\\") != std::string::npos)
|
|
_fname.replace(_fname.find("\\\\"), 2, "/");
|
|
while(_fname.find('\\') != std::string::npos)
|
|
_fname.replace(_fname.find('\\'), 1, "/");
|
|
|
|
return _fname.substr(0, _fname.find_last_of('/'));
|
|
#elif defined(TIMEMORY_WINDOWS)
|
|
while(_fname.find('/') != std::string::npos)
|
|
_fname.replace(_fname.find('/'), 1, "\\");
|
|
|
|
_fname = _fname.substr(0, _fname.find_last_of('\\'));
|
|
return (_fname.at(_fname.length() - 1) == '\\')
|
|
? _fname.substr(0, _fname.length() - 1)
|
|
: _fname;
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------//
|
|
|
|
int
|
|
makedir(std::string _dir, int umask)
|
|
{
|
|
#if defined(TIMEMORY_UNIX)
|
|
while(_dir.find("\\\\") != std::string::npos)
|
|
_dir.replace(_dir.find("\\\\"), 2, "/");
|
|
while(_dir.find('\\') != std::string::npos)
|
|
_dir.replace(_dir.find('\\'), 1, "/");
|
|
|
|
if(_dir.length() == 0)
|
|
return 0;
|
|
|
|
int ret = mkdir(_dir.c_str(), umask);
|
|
if(ret != 0)
|
|
{
|
|
int err = errno;
|
|
if(err != EEXIST)
|
|
{
|
|
std::cerr << "mkdir(" << _dir.c_str() << ", " << umask
|
|
<< ") returned: " << ret << std::endl;
|
|
std::stringstream _sdir;
|
|
_sdir << "/bin/mkdir -p " << _dir;
|
|
return (launch_process(_sdir.str().c_str())) ? 0 : 1;
|
|
}
|
|
}
|
|
#elif defined(TIMEMORY_WINDOWS)
|
|
consume_parameters(umask);
|
|
while(_dir.find('/') != std::string::npos)
|
|
_dir.replace(_dir.find('/'), 1, "\\");
|
|
|
|
if(_dir.length() == 0)
|
|
return 0;
|
|
|
|
int ret = _mkdir(_dir.c_str());
|
|
if(ret != 0)
|
|
{
|
|
int err = errno;
|
|
if(err != EEXIST)
|
|
{
|
|
std::cerr << "_mkdir(" << _dir.c_str() << ") returned: " << ret << std::endl;
|
|
std::stringstream _sdir;
|
|
_sdir << "mkdir " << _dir;
|
|
return (launch_process(_sdir.str().c_str())) ? 0 : 1;
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------//
|
|
|
|
bool
|
|
get_bool(const std::string& strbool, bool _default) noexcept
|
|
{
|
|
// empty string returns default
|
|
if(strbool.empty())
|
|
return _default;
|
|
|
|
// check if numeric
|
|
if(strbool.find_first_not_of("0123456789") == std::string::npos)
|
|
{
|
|
if(strbool.length() > 1 || strbool[0] != '0')
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// convert to lowercase
|
|
auto _val = std::string{ strbool };
|
|
for(auto& itr : _val)
|
|
itr = tolower(itr);
|
|
|
|
// check for matches to acceptable forms of false
|
|
for(const auto& itr : { "off", "false", "no", "n", "f" })
|
|
{
|
|
if(_val == itr)
|
|
return false;
|
|
}
|
|
|
|
// check for matches to acceptable forms of true
|
|
for(const auto& itr : { "on", "true", "yes", "y", "t" })
|
|
{
|
|
if(_val == itr)
|
|
return true;
|
|
}
|
|
|
|
return _default;
|
|
}
|
|
//
|
|
//--------------------------------------------------------------------------------------//
|
|
//
|
|
#if defined(TIMEMORY_UNIX)
|
|
//
|
|
std::string
|
|
demangle_backtrace(const char* cstr)
|
|
{
|
|
auto _trim = [](std::string& _sub, size_t& _len) {
|
|
size_t _pos = 0;
|
|
while(!_sub.empty() && (_pos = _sub.find_first_of(' ')) == 0)
|
|
{
|
|
_sub = _sub.erase(_pos, 1);
|
|
--_len;
|
|
}
|
|
while(!_sub.empty() && (_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
|
|
{
|
|
_sub = _sub.substr(0, _sub.length() - 1);
|
|
--_len;
|
|
}
|
|
return _sub;
|
|
};
|
|
|
|
auto _save = std::string{ cstr };
|
|
auto str = demangle(std::string(cstr));
|
|
if(str.empty())
|
|
return str;
|
|
auto beg = str.find("(");
|
|
if(beg == std::string::npos)
|
|
{
|
|
beg = str.find("_Z");
|
|
if(beg != std::string::npos)
|
|
beg -= 1;
|
|
}
|
|
auto end = str.find("+", beg);
|
|
if(beg != std::string::npos && end != std::string::npos)
|
|
{
|
|
auto len = end - (beg + 1);
|
|
auto sub = str.substr(beg + 1, len);
|
|
auto dem = demangle(_trim(sub, len));
|
|
str = str.replace(beg + 1, len, dem);
|
|
}
|
|
else if(beg != std::string::npos)
|
|
{
|
|
auto len = str.length() - (beg + 1);
|
|
auto sub = str.substr(beg + 1, len);
|
|
auto dem = demangle(_trim(sub, len));
|
|
str = str.replace(beg + 1, len, dem);
|
|
}
|
|
else if(end != std::string::npos)
|
|
{
|
|
auto len = end;
|
|
auto sub = str.substr(beg, len);
|
|
auto dem = demangle(_trim(sub, len));
|
|
str = str.replace(beg, len, dem);
|
|
}
|
|
|
|
if(str.empty())
|
|
{
|
|
TIMEMORY_TESTING_EXCEPTION(__FUNCTION__ << " resulted in empty string. input: "
|
|
<< _save);
|
|
return _save;
|
|
}
|
|
|
|
// cleanup std::_1::basic_<...> types since demangled versions are for diagnostics
|
|
using pair_t = std::pair<std::string, std::string>;
|
|
for(auto&& itr : { pair_t{ demangle<std::string>(), "std::string" },
|
|
pair_t{ demangle<std::istream>(), "std::istream" },
|
|
pair_t{ demangle<std::ostream>(), "std::ostream" },
|
|
pair_t{ demangle<std::stringstream>(), "std::stringstream" },
|
|
pair_t{ demangle<std::istringstream>(), "std::istringstream" },
|
|
pair_t{ demangle<std::ostringstream>(), "std::ostringstream" } })
|
|
str = str_transform(str, itr.first, "", [itr](const std::string&) -> std::string {
|
|
return itr.second;
|
|
});
|
|
return str;
|
|
}
|
|
//
|
|
std::string
|
|
demangle_backtrace(const std::string& str)
|
|
{
|
|
return demangle_backtrace(str.c_str());
|
|
}
|
|
//
|
|
std::string
|
|
demangle_unw_backtrace(const char* cstr)
|
|
{
|
|
auto _save = std::string{ cstr };
|
|
auto _str = tim::demangle(cstr);
|
|
if(_str.empty())
|
|
return _str;
|
|
auto _beg = _str.find("_Z");
|
|
auto _end = _str.find(" ", _beg);
|
|
if(_beg != std::string::npos && _end != std::string::npos)
|
|
{
|
|
auto _len = _end - _beg;
|
|
auto _sub = _str.substr(_beg, _len);
|
|
auto _dem = demangle(_sub);
|
|
_str = _str.replace(_beg, _len, _dem);
|
|
}
|
|
|
|
if(_str.empty())
|
|
{
|
|
TIMEMORY_TESTING_EXCEPTION(__FUNCTION__ << " resulted in empty string. input: "
|
|
<< _save);
|
|
return _save;
|
|
}
|
|
|
|
// cleanup std::_1::basic_<...> types since demangled versions are for diagnostics
|
|
using pair_t = std::pair<std::string, std::string>;
|
|
for(auto&& itr : { pair_t{ demangle<std::string>(), "std::string" },
|
|
pair_t{ demangle<std::istream>(), "std::istream" },
|
|
pair_t{ demangle<std::ostream>(), "std::ostream" },
|
|
pair_t{ demangle<std::stringstream>(), "std::stringstream" },
|
|
pair_t{ demangle<std::istringstream>(), "std::istringstream" },
|
|
pair_t{ demangle<std::ostringstream>(), "std::ostringstream" } })
|
|
_str =
|
|
str_transform(_str, itr.first, "", [itr](const std::string&) -> std::string {
|
|
return itr.second;
|
|
});
|
|
|
|
return _str;
|
|
}
|
|
//
|
|
std::string
|
|
demangle_unw_backtrace(const std::string& _str)
|
|
{
|
|
return demangle_unw_backtrace(_str.c_str());
|
|
}
|
|
//
|
|
#endif // defined(TIMEMORY_UNIX)
|
|
//
|
|
std::vector<std::string>
|
|
read_command_line(pid_t _pid)
|
|
{
|
|
std::vector<std::string> _cmdline;
|
|
#if defined(TIMEMORY_LINUX)
|
|
std::stringstream fcmdline;
|
|
fcmdline << "/proc/" << _pid << "/cmdline";
|
|
std::ifstream ifs(fcmdline.str().c_str());
|
|
if(ifs)
|
|
{
|
|
char cstr;
|
|
std::string sarg;
|
|
while(!ifs.eof())
|
|
{
|
|
ifs >> cstr;
|
|
if(!ifs.eof())
|
|
{
|
|
if(cstr != '\0')
|
|
{
|
|
sarg += cstr;
|
|
}
|
|
else
|
|
{
|
|
_cmdline.push_back(sarg);
|
|
sarg = "";
|
|
}
|
|
}
|
|
}
|
|
ifs.close();
|
|
}
|
|
|
|
#else
|
|
consume_parameters(_pid);
|
|
#endif
|
|
return _cmdline;
|
|
}
|
|
//
|
|
namespace utility
|
|
{
|
|
//
|
|
path::path(const std::string& _path)
|
|
: std::string(osrepr(_path))
|
|
{}
|
|
|
|
path::path(char* _path)
|
|
: std::string(osrepr(std::string(_path)))
|
|
{}
|
|
|
|
path::path(const path& rhs)
|
|
: std::string(osrepr(rhs))
|
|
{}
|
|
|
|
path::path(const char* _path)
|
|
: std::string(osrepr(std::string(const_cast<char*>(_path))))
|
|
{}
|
|
|
|
path&
|
|
path::operator=(const std::string& rhs)
|
|
{
|
|
std::string::operator=(osrepr(rhs));
|
|
return *this;
|
|
}
|
|
|
|
path&
|
|
path::operator=(const path& rhs)
|
|
{
|
|
if(this != &rhs)
|
|
std::string::operator=(osrepr(rhs));
|
|
return *this;
|
|
}
|
|
|
|
path&
|
|
path::insert(size_type __pos, const std::string& __s)
|
|
{
|
|
std::string::operator=(osrepr(std::string::insert(__pos, __s)));
|
|
return *this;
|
|
}
|
|
|
|
path&
|
|
path::insert(size_type __pos, const path& __s)
|
|
{
|
|
std::string::operator=(osrepr(std::string::insert(__pos, __s)));
|
|
return *this;
|
|
}
|
|
|
|
TIMEMORY_UTILITY_INLINE std::string
|
|
path::os()
|
|
{
|
|
#if defined(TIMEMORY_WINDOWS)
|
|
return "\\";
|
|
#elif defined(TIMEMORY_UNIX)
|
|
return "/";
|
|
#endif
|
|
}
|
|
|
|
TIMEMORY_UTILITY_INLINE std::string
|
|
path::inverse()
|
|
{
|
|
#if defined(TIMEMORY_WINDOWS)
|
|
return "/";
|
|
#elif defined(TIMEMORY_UNIX)
|
|
return "\\";
|
|
#endif
|
|
}
|
|
|
|
// OS-dependent representation
|
|
TIMEMORY_UTILITY_INLINE std::string
|
|
path::osrepr(std::string _path)
|
|
{
|
|
#if defined(TIMEMORY_WINDOWS)
|
|
while(_path.find('/') != std::string::npos)
|
|
_path.replace(_path.find('/'), 1, "\\");
|
|
#elif defined(TIMEMORY_UNIX)
|
|
while(_path.find("\\\\") != std::string::npos)
|
|
_path.replace(_path.find("\\\\"), 2, "/");
|
|
while(_path.find('\\') != std::string::npos)
|
|
_path.replace(_path.find('\\'), 1, "/");
|
|
#endif
|
|
return _path;
|
|
}
|
|
//
|
|
} // namespace utility
|
|
} // namespace tim
|
|
//
|
|
|
|
#endif // !defined(TIMEMORY_UTILITY_UTILITY_CPP_)
|