/** * @file utils/Trace.hpp * @author See the AUTHORS file */ /* * Copyright (C) 2012-2017 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 < typename T, typename U, typename V, typename W > class AbstractCoupledModel; template < typename T, typename U, typename V > class AbstractAtomicModel; template < typename Time, typename Parameters > class AbstractModel; template < typename T, typename U, typename V > class Internals; template < typename T, typename U, typename V > 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 < std::string, int > elt_dictionary; static std::vector < std::string > 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 Time > class TraceElement { template < typename T, typename U, typename V, typename W > friend class artis::kernel::AbstractCoupledModel; template < typename T, typename U, typename V > friend class artis::kernel::AbstractAtomicModel; template < typename T, typename P > friend class artis::kernel::AbstractModel; template < typename T, typename U, typename V > friend class artis::kernel::Internals; template < typename T, typename U, typename V > 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 Time > class TraceElements : public std::vector < TraceElement < Time > > { public: TraceElements() { } virtual ~TraceElements() { } TraceElements filter_model_name( const std::string& model_name) const { TraceElements < Time > result; std::copy_if( TraceElements < Time >::begin(), TraceElements < Time >::end(), std::back_inserter(result), [model_name](TraceElement < Time > 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 < Time >::begin(), TraceElements < Time >::end(), std::back_inserter(result), [time](TraceElement < Time > const & x) { return x.get_time() == time; }); return result; } TraceElements filter_type(TraceType type) const { TraceElements result; std::copy_if(TraceElements < Time >::begin(), TraceElements < Time >::end(), std::back_inserter(result), [type](TraceElement < Time > const & x) { return x.get_type() == type; }); return result; } TraceElements filter_variable(const std::string& var_name) const { TraceElements result; std::copy_if(TraceElements < Time >::begin(), TraceElements < Time >::end(), std::back_inserter(result), [var_name](TraceElement < Time > 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 < Time >::const_iterator it = TraceElements < Time >::begin(); it != TraceElements < Time >::end(); ++it) { ss << it->to_string(date_format) << std::endl; } return ss.str(); } }; template < class Time > class Trace { public: virtual ~Trace() { } static Trace& trace() { std::call_once(_flag, [] () { _instance.reset(new Trace()); } ); return *_instance; } void clear() { _trace.clear(); } const TraceElements < Time >& 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 < Time >& 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 < Trace < Time > > _instance; static std::once_flag _flag; TraceElements < Time > _trace; TraceElement < Time > _element; std::ostringstream* _sstream; std::mutex _mutex; }; } } template < class Time > artis::utils::Trace < Time >& operator<<( artis::utils::Trace < Time >& trace, const artis::utils::TraceElement < Time >& e) { std::lock_guard < std::mutex > lock(trace.mutex()); trace.set_element(e); return trace; } template < class Time > artis::utils::Trace < Time >& operator<<( artis::utils::Trace < Time >& trace, const artis::utils::KernelInfo& info) { std::lock_guard < std::mutex > lock(trace.mutex()); trace.set_kernel_info(info); return trace; } template < class Time > artis::utils::Trace < Time >& operator<<( artis::utils::Trace < Time >& trace, const std::string& str) { std::lock_guard < std::mutex > lock(trace.mutex()); trace.sstream() << str; return trace; } template < class Time > artis::utils::Trace < Time >& operator<<( artis::utils::Trace < Time >& trace, typename Time::type t) { std::lock_guard < std::mutex > lock(trace.mutex()); trace.sstream() << t; return trace; } template < class Time > std::shared_ptr < artis::utils::Trace < Time > > artis::utils::Trace < Time >::_instance; template < class Time > std::once_flag artis::utils::Trace < Time >::_flag; #endif