/**
* @file utils/Trace.hpp
* @author See the AUTHORS file
*/
/*
* Copyright (C) 2012-2019 ULCO http://www.univ-littoral.fr
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef ARTIS_UTILS_TRACE
#define ARTIS_UTILS_TRACE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if WIN32
#include
#endif
//fwd decl for friend classes in TraceElement
namespace artis {
namespace kernel {
template
class AbstractCoupledModel;
template
class AbstractAtomicModel;
template
class AbstractModel;
template
class Internals;
template
class Externals;
}
}
namespace artis {
namespace utils {
enum TraceType {
NONE = 0, CHECK = 1, CONSTRUCT, SUBMODEL_ADD, INTERNAL_DECL,
EXTERNAL_DECL, INTERNAL_LINK, INIT, START, BEFORE_COMPUTE,
COMPUTE, PUT, AFTER_COMPUTE, DESTRUCT, KERNEL
};
static const std::vector TraceTypesStr = {
"none", "check", "construct", "submodel_add", "internal_decl",
"external_decl", "internal_link", "init", "start", "before_compute",
"compute", "put", "after_compute", "destruct", "kernel"};
class KernelInfo {
public:
static std::map elt_dictionary;
static std::vector elt_names;
static unsigned int term(const std::string& v)
{
if (elt_dictionary.find(v) == elt_dictionary.end()) {
elt_dictionary[v] = elt_names.size();
elt_names.push_back(v);
}
return elt_dictionary[v];
}
static const std::string& term(unsigned int i) { return elt_names[i]; }
KernelInfo()
:
_internal_var(false), _empty(true)
{
set_var("");
set_value("");
set_tgt_model("");
set_tgt_internal_var("");
}
KernelInfo(const std::string& var, bool internal_var,
const std::string& value)
:
_internal_var(internal_var), _empty(false)
{
set_var(var);
set_value(value);
set_tgt_model("");
set_tgt_internal_var("");
}
KernelInfo(const std::string& var, const std::string& tgt_model,
const std::string& tgt_internal_var)
:
_internal_var(true), _empty(false)
{
set_var(var);
set_value("");
set_tgt_model(tgt_model);
set_tgt_internal_var(tgt_internal_var);
}
KernelInfo(const std::string& var, bool internal_var)
:
_internal_var(internal_var), _empty(false)
{
set_var(var);
set_value("");
set_tgt_model("");
set_tgt_internal_var("");
}
KernelInfo(const std::string& tgt_model)
:
_internal_var(false), _empty(false)
{
set_var("");
set_value("");
set_tgt_model(tgt_model);
set_tgt_internal_var("");
}
void set_var(const std::string& v) { _var = KernelInfo::term(v); }
void set_value(const std::string& v) { _value = KernelInfo::term(v); }
void set_tgt_model(const std::string& v) { _tgt_model = KernelInfo::term(v); }
void set_tgt_internal_var(const std::string& v) { _tgt_internal_var = KernelInfo::term(v); }
const std::string& var() const { return KernelInfo::term(_var); }
const std::string& value() const { return KernelInfo::term(_value); }
const std::string& tgt_model() const { return KernelInfo::term(_tgt_model); }
const std::string& tgt_internal_var() const { return KernelInfo::term(_tgt_internal_var); }
unsigned int var_idx() const { return _var; }
unsigned int tgt_internal_var_idx() const { return _tgt_internal_var; }
unsigned int tgt_model_idx() const { return _tgt_model; }
bool is_internal_var() const { return _internal_var; }
bool empty() const { return _empty; }
std::string to_string() const
{
std::ostringstream ss;
if (not KernelInfo::term(_var).empty()) {
ss << ":";
if (not _internal_var)
ss << "*";
ss << KernelInfo::term(_var);
}
if (not KernelInfo::term(_value).empty()) {
ss << "=" << KernelInfo::term(_value);
}
if (not KernelInfo::term(_tgt_model).empty()) {
ss << " -> " << KernelInfo::term(_tgt_model);
if (not KernelInfo::term(_tgt_internal_var).empty()) {
ss << ":" << KernelInfo::term(_tgt_internal_var);
}
}
return ss.str();
}
private:
unsigned int _var;
unsigned int _value;
unsigned int _tgt_model;
unsigned int _tgt_internal_var;
bool _internal_var;
bool _empty;
};
template
class TraceElement {
template
friend
class artis::kernel::AbstractCoupledModel;
template
friend
class artis::kernel::AbstractAtomicModel;
template
friend
class artis::kernel::AbstractModel;
template
friend
class artis::kernel::Internals;
template
friend
class artis::kernel::Externals;
private:
TraceElement(bool from_kernel, const std::string& model_name,
typename Time::type time, TraceType type)
:
_time(time), _type(type),
_from_kernel(from_kernel)
{
_model_name = KernelInfo::term(model_name);
}
public:
TraceElement()
:_time(Time::null), _type(NONE),
_from_kernel(false) { }
TraceElement(const std::string& model_name, typename Time::type time,
TraceType type)
:
_time(time), _type(type),
_from_kernel(false)
{
_model_name = KernelInfo::term(model_name);
}
virtual ~TraceElement() { }
const std::string& get_comment() const { return _comment; }
const std::string& get_model_name() const { return KernelInfo::term(_model_name); }
unsigned int get_model_name_idx() const { return _model_name; }
typename Time::type get_time() const { return _time; }
TraceType get_type() const { return _type; }
const KernelInfo& get_kernel_info() const { return _kernel_info; }
void set_comment(const std::string& comment) { _comment = comment; }
bool from_kernel() const { return _from_kernel; }
void set_kernel_info(const KernelInfo& info) { _kernel_info = info; }
std::string to_string(artis::utils::DateFormat date_format =
artis::utils::DATE_FORMAT_EXTENDED) const
{
std::ostringstream ss;
ss << (from_kernel() ? "KERNEL" : "TRACE ");
if (get_time() != Time::null) {
ss << "(" << utils::DateTime::toJulianDayFmt(get_time(),
date_format)
<< ")";
}
ss << ": ";
ss << "<" + TraceTypesStr[get_type()] + ">";
ss << " " << get_model_name();
if (not get_kernel_info().empty()) {
ss << get_kernel_info().to_string();
}
if (not get_comment().empty()) {
ss << " => " << get_comment();
}
return ss.str();
}
private:
unsigned int _model_name;
typename Time::type _time;
TraceType _type;
std::string _comment;
KernelInfo _kernel_info;
bool _from_kernel;
};
template
class TraceElements : public std::vector > {
public:
TraceElements() { }
virtual ~TraceElements() { }
TraceElements filter_model_name(
const std::string& model_name) const
{
TraceElements result;
std::copy_if(
TraceElements::begin(),
TraceElements::end(), std::back_inserter(result),
[model_name](TraceElement const& x) {
if (not x.get_kernel_info().empty()) {
if (x.get_kernel_info().tgt_model() == model_name) {
return true;
}
}
return x.get_model_name() == model_name;
});
return result;
}
TraceElements filter_time(typename Time::type time) const
{
TraceElements result;
std::copy_if(TraceElements::begin(),
TraceElements::end(), std::back_inserter(result),
[time](TraceElement const& x) { return x.get_time() == time; });
return result;
}
TraceElements filter_type(TraceType type) const
{
TraceElements result;
std::copy_if(TraceElements::begin(),
TraceElements::end(), std::back_inserter(result),
[type](TraceElement const& x) { return x.get_type() == type; });
return result;
}
TraceElements filter_variable(const std::string& var_name) const
{
TraceElements result;
std::copy_if(TraceElements::begin(),
TraceElements::end(), std::back_inserter(result),
[var_name](TraceElement const& x) {
if (x.get_kernel_info().empty())
return false;
return ((x.get_kernel_info().var() == var_name)
or (x.get_kernel_info().tgt_internal_var() == var_name));
});
return result;
}
std::string to_string(artis::utils::DateFormat date_format =
artis::utils::DATE_FORMAT_EXTENDED) const
{
std::ostringstream ss;
for (typename TraceElements::const_iterator it =
TraceElements::begin();
it != TraceElements::end(); ++it) {
ss << it->to_string(date_format) << std::endl;
}
return ss.str();
}
};
template
class Trace {
public:
virtual ~Trace() { }
static Trace& trace()
{
std::call_once(_flag, []() { _instance.reset(new Trace()); }
);
return *_instance;
}
void clear() { _trace.clear(); }
const TraceElements& elements() const { return _trace; }
void flush()
{
if (_sstream) {
_element.set_comment(_sstream->str());
delete _sstream;
_sstream = 0;
}
_trace.push_back(_element);
}
std::mutex& mutex() { return _mutex; }
void set_element(const TraceElement& element) { _element = element; }
void set_kernel_info(const KernelInfo& info) { _element.set_kernel_info(info); }
std::ostringstream& sstream()
{
if (_sstream == 0) {
_sstream = new std::ostringstream();
}
return *_sstream;
}
private:
Trace() { _sstream = 0; }
static std::shared_ptr > _instance;
static std::once_flag _flag;
TraceElements _trace;
TraceElement _element;
std::ostringstream* _sstream;
std::mutex _mutex;
};
}
}
template
artis::utils::Trace& operator<<(
artis::utils::Trace& trace,
const artis::utils::TraceElement& e)
{
std::lock_guard lock(trace.mutex());
trace.set_element(e);
return trace;
}
template
artis::utils::Trace& operator<<(
artis::utils::Trace& trace,
const artis::utils::KernelInfo& info)
{
std::lock_guard lock(trace.mutex());
trace.set_kernel_info(info);
return trace;
}
template
artis::utils::Trace& operator<<(
artis::utils::Trace& trace,
const std::string& str)
{
std::lock_guard lock(trace.mutex());
trace.sstream() << str;
return trace;
}
template
artis::utils::Trace& operator<<(
artis::utils::Trace& trace,
typename Time::type t)
{
std::lock_guard lock(trace.mutex());
trace.sstream() << t;
return trace;
}
template
std::shared_ptr >
artis::utils::Trace::_instance;
template
std::once_flag artis::utils::Trace::_flag;
#endif