vtk-m/vtkm/cont/Logging.cxx
Kenneth Moreland 3e1339f9a7 Remove deprecated features from VTK-m
With the major revision 2.0 of VTK-m, many items previously marked as
deprecated were removed. If updating to a new version of VTK-m, it is
recommended to first update to VTK-m 1.9, which will include the deprecated
features but provide warnings (with the right compiler) that will point to
the replacement code. Once the deprecations have been fixed, updating to
2.0 should be smoother.
2022-11-17 07:12:31 -06:00

403 lines
9.2 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/Logging.h>
#ifdef VTKM_ENABLE_LOGGING
// disable MSVC warnings in loguru.hpp
#ifdef VTKM_MSVC
#pragma warning(push)
#pragma warning(disable : 4722)
#endif // VTKM_MSVC
#define LOGURU_USE_ANONYMOUS_NAMESPACE
#define LOGURU_WITH_STREAMS 1
#define LOGURU_SCOPE_TIME_PRECISION 6
#include <vtkm/thirdparty/loguru/vtkmloguru/loguru.cpp>
#ifdef VTKM_MSVC
#pragma warning(pop)
#endif // VTKM_MSVC
#endif // VTKM_ENABLE_LOGGING
#include <cassert>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
namespace
{
// This won't be needed under C++14, as strongly typed enums are automatically
// hashed then. But for now...
struct LogHasher
{
std::size_t operator()(vtkm::cont::LogLevel level) const
{
return static_cast<std::size_t>(level);
}
};
using LevelMapType = std::unordered_map<vtkm::cont::LogLevel, std::string, LogHasher>;
static bool Initialized = false;
static LevelMapType LogLevelNames;
void setLogLevelName(vtkm::cont::LogLevel level, const std::string& name) noexcept
{
// if the log has been initialized, prevent modifications of the name map
// to prevent race conditions.
if (!Initialized)
{
LogLevelNames[level] = name;
}
}
// Throws std::out_of_range if level not found.
const std::string& getLogLevelName(vtkm::cont::LogLevel level)
{
const LevelMapType& names = LogLevelNames;
return names.at(static_cast<vtkm::cont::LogLevel>(level));
}
#ifdef VTKM_ENABLE_LOGGING
const char* verbosityToNameCallback(loguru::Verbosity v)
{
try
{
// Calling c_str on const string&.
return getLogLevelName(static_cast<vtkm::cont::LogLevel>(v)).c_str();
}
catch (std::out_of_range&)
{
return nullptr;
}
}
loguru::Verbosity nameToVerbosityCallback(const char* name)
{
const LevelMapType& names = LogLevelNames;
for (auto& kv : names)
{
if (kv.second == name)
{
return static_cast<loguru::Verbosity>(kv.first);
}
}
return loguru::Verbosity_INVALID;
}
#endif // VTKM_ENABLE_LOGGING
} // end anon namespace
namespace vtkm
{
namespace cont
{
VTKM_CONT
void InitLogging(int& argc, char* argv[], const std::string& loggingFlag)
{
SetLogLevelName(vtkm::cont::LogLevel::Off, "Off");
SetLogLevelName(vtkm::cont::LogLevel::Fatal, "FATL");
SetLogLevelName(vtkm::cont::LogLevel::Error, "ERR");
SetLogLevelName(vtkm::cont::LogLevel::Warn, "WARN");
SetLogLevelName(vtkm::cont::LogLevel::Info, "Info");
SetLogLevelName(vtkm::cont::LogLevel::DevicesEnabled, "Dev");
SetLogLevelName(vtkm::cont::LogLevel::Perf, "Perf");
SetLogLevelName(vtkm::cont::LogLevel::MemCont, "MemC");
SetLogLevelName(vtkm::cont::LogLevel::MemExec, "MemE");
SetLogLevelName(vtkm::cont::LogLevel::MemTransfer, "MemT");
SetLogLevelName(vtkm::cont::LogLevel::KernelLaunches, "Kern");
SetLogLevelName(vtkm::cont::LogLevel::Cast, "Cast");
#ifdef VTKM_ENABLE_LOGGING
if (!Initialized)
{
loguru::set_verbosity_to_name_callback(&verbosityToNameCallback);
loguru::set_name_to_verbosity_callback(&nameToVerbosityCallback);
// Set the default log level to warning
SetStderrLogLevel(vtkm::cont::LogLevel::Warn);
loguru::init(argc, argv, loggingFlag.c_str());
}
#else // VTKM_ENABLE_LOGGING
(void)argc;
(void)argv;
(void)loggingFlag;
#endif // VTKM_ENABLE_LOGGING
// Prevent LogLevelNames from being modified (makes thread safety easier)
Initialized = true;
}
void InitLogging()
{
int argc = 1;
char dummy[1] = { '\0' };
char* argv[2] = { dummy, nullptr };
InitLogging(argc, argv);
}
VTKM_CONT
void SetStderrLogLevel(const char* verbosity)
{
#ifdef VTKM_ENABLE_LOGGING
loguru::g_stderr_verbosity = loguru::get_verbosity_from_name(verbosity);
#else // VTKM_ENABLE_LOGGING
(void)verbosity;
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
void SetStderrLogLevel(LogLevel level)
{
#ifdef VTKM_ENABLE_LOGGING
loguru::g_stderr_verbosity = static_cast<loguru::Verbosity>(level);
#else // VTKM_ENABLE_LOGGING
(void)level;
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
vtkm::cont::LogLevel GetStderrLogLevel()
{
#ifdef VTKM_ENABLE_LOGGING
return static_cast<vtkm::cont::LogLevel>(loguru::g_stderr_verbosity);
#else // VTKM_ENABLE_LOGGING
return vtkm::cont::LogLevel::Off;
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
void SetLogThreadName(const std::string& name)
{
#ifdef VTKM_ENABLE_LOGGING
loguru::set_thread_name(name.c_str());
#else // VTKM_ENABLE_LOGGING
(void)name;
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
std::string GetLogThreadName()
{
#ifdef VTKM_ENABLE_LOGGING
char buffer[128];
loguru::get_thread_name(buffer, 128, false);
return buffer;
#else // VTKM_ENABLE_LOGGING
return "N/A";
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
std::string GetLogErrorContext()
{
#ifdef VTKM_ENABLE_LOGGING
auto ctx = loguru::get_error_context();
return ctx.c_str();
#else // VTKM_ENABLE_LOGGING
return "N/A";
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT
std::string GetStackTrace(vtkm::Int32 skip)
{
(void)skip; // unsed when logging disabled.
std::string result;
#ifdef VTKM_ENABLE_LOGGING
result = loguru::stacktrace(skip + 2).c_str();
#endif // VTKM_ENABLE_LOGGING
if (result.empty())
{
result = "(Stack trace unavailable)";
}
return result;
}
namespace
{
/// Convert a size in bytes to a human readable string (e.g. "64 bytes",
/// "1.44 MiB", "128 GiB", etc). @a prec controls the fixed point precision
/// of the stringified number.
inline VTKM_CONT std::string HumanSize(vtkm::UInt64 bytes, int prec = 2)
{
vtkm::UInt64 current = bytes;
vtkm::UInt64 previous = bytes;
constexpr static const char* units[] = { "bytes", "KiB", "MiB", "GiB", "TiB", "PiB" };
//this way reduces the number of float divisions we do
int i = 0;
while (current > 1024)
{
previous = current;
current = current >> 10; //shift up by 1024
++i;
}
const double bytesf =
(i == 0) ? static_cast<double>(previous) : static_cast<double>(previous) / 1024.;
std::ostringstream out;
out << std::fixed << std::setprecision(prec) << bytesf << " " << units[i];
return out.str();
}
}
VTKM_CONT
std::string GetHumanReadableSize(vtkm::UInt64 bytes, int prec)
{
return HumanSize(bytes, prec);
}
VTKM_CONT
std::string GetSizeString(vtkm::UInt64 bytes, int prec)
{
return HumanSize(bytes, prec) + " (" + std::to_string(bytes) + " bytes)";
}
VTKM_CONT
void SetLogLevelName(LogLevel level, const std::string& name)
{
if (Initialized)
{
VTKM_LOG_F(LogLevel::Error, "SetLogLevelName called after InitLogging.");
return;
}
setLogLevelName(level, name);
}
VTKM_CONT
std::string GetLogLevelName(LogLevel level)
{
#ifdef VTKM_ENABLE_LOGGING
{ // Check loguru lookup first:
const char* name = loguru::get_verbosity_name(static_cast<loguru::Verbosity>(level));
if (name)
{
return name;
}
}
#else
{
try
{
return getLogLevelName(level);
}
catch (std::out_of_range&)
{ /* fallthrough */
}
}
#endif
// Create a string from the numeric value otherwise:
using T = std::underlying_type<LogLevel>::type;
return std::to_string(static_cast<T>(level));
}
VTKM_CONT std::string TypeToString(const std::type_info& t)
{
#ifdef VTKM_ENABLE_LOGGING
return loguru::demangle(t.name()).c_str();
#else // VTKM_ENABLE_LOGGING
return t.name();
#endif // VTKM_ENABLE_LOGGING
}
VTKM_CONT std::string TypeToString(const std::type_index& t)
{
#ifdef VTKM_ENABLE_LOGGING
return loguru::demangle(t.name()).c_str();
#else // VTKM_ENABLE_LOGGING
return t.name();
#endif // VTKM_ENABLE_LOGGING
}
#ifdef VTKM_ENABLE_LOGGING
VTKM_CONT
int getVerbosityByLevel(LogLevel level)
{
return static_cast<loguru::Verbosity>(level);
}
namespace detail
{
struct LogScope::InternalStruct : loguru::LogScopeRAII
{
template <typename... Ts>
InternalStruct(Ts&&... args)
: loguru::LogScopeRAII(std::forward<Ts>(args)...)
{
}
};
VTKM_CONT
LogScope::LogScope(LogLevel level, const char* file, unsigned line, const char* format...)
{
auto verbosity = getVerbosityByLevel(level);
if (verbosity > loguru::current_verbosity_cutoff())
{
this->Internals = std::make_unique<InternalStruct>();
}
else
{
va_list args;
va_start(args, format);
this->Internals = std::make_unique<InternalStruct>(verbosity, file, line, format, args);
va_end(args);
}
}
LogScope::~LogScope() = default;
} // namespace detail
VTKM_CONT
void LogCond(LogLevel level, bool cond, const char* file, unsigned line, const char* format...)
{
if (cond)
{
auto verbosity = getVerbosityByLevel(level);
if (verbosity <= loguru::current_verbosity_cutoff())
{
va_list args;
va_start(args, format);
loguru::vlog(verbosity, file, line, format, args);
va_end(args);
}
}
}
VTKM_CONT
LogCondStream::~LogCondStream() noexcept(false)
{
LogCond(this->Level, this->Condition, this->File, this->Line, this->SStream.str().c_str());
}
#endif // VTKM_ENABLE_LOGGING
}
} // end namespace vtkm::cont