/** * @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 #if WIN32 #include #endif #ifdef WITH_TRACE //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; }} #endif namespace artis { namespace utils { enum TraceType { NONE = 0, CHECK, 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: const std::string& var() const {return _var;} std::string value() const {return _value;} std::string tgt_model() const {return _tgt_model;} std::string tgt_internal_var() const {return _tgt_internal_var;} bool internal_var() const {return _internal_var;} bool empty() const {return _empty;} KernelInfo() : _var(""), _internal_var(false), _value(""), _tgt_model(""), _tgt_internal_var(""), _empty(true) { } KernelInfo(const std::string& var, bool internal_var, const std::string& value) : _var(var), _internal_var(internal_var), _value(value), _tgt_model(""), _tgt_internal_var(""), _empty(false) { } KernelInfo(const std::string& var, const std::string& tgt_model, const std::string& tgt_internal_var) : _var(var), _internal_var(true), _value(""), _tgt_model(tgt_model), _tgt_internal_var(tgt_internal_var), _empty(false) { } KernelInfo(const std::string& var, bool internal_var) : _var(var), _internal_var(internal_var), _value(""), _tgt_model(""), _tgt_internal_var(""), _empty(false) { } KernelInfo(const std::string& tgt_model) : _var(""), _internal_var(false), _value(""), _tgt_model(tgt_model), _tgt_internal_var(""), _empty(false) { } std::string to_string() const { std::ostringstream ss; if( not _var.empty() ){ ss << ":"; if (not _internal_var) ss << "*"; ss << _var; } if( not _value.empty()) { ss << "=" << _value; } if(not _tgt_model.empty()) { ss << " -> " << _tgt_model; if(not _tgt_internal_var.empty()) { ss << ":" << _tgt_internal_var; } } return ss.str(); } private: std::string _var; bool _internal_var; std::string _value; std::string _tgt_model; std::string _tgt_internal_var; bool _empty; }; template < class Time > class TraceElement { public: TraceElement() : _time(Time::null), _type(NONE), _from_kernel(false) { } TraceElement(const std::string& model_name, typename Time::type time, TraceType type) : _model_name(model_name), _time(time), _type(type), _from_kernel(false) { } virtual ~TraceElement() { } const std::string& get_comment() const { return _comment; } const std::string& get_model_name() 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; } private: std::string _model_name; typename Time::type _time; TraceType _type; std::string _comment; KernelInfo _kernel_info; bool _from_kernel; #ifdef WITH_TRACE 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 Time, typename Parameters > 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) : _model_name(model_name), _time(time), _type(type), _from_kernel(from_kernel) { } #endif }; 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) { 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; } 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->from_kernel() ? "KERNEL" : "TRACE"); if(it->get_time() != Time::null) { ss << "(" << utils::DateTime::toJulianDayFmt(it->get_time(), date_format) << ")"; } ss << ": "; ss << "<" + TraceTypesStr[it->get_type()] + ">"; ss << " " << it->get_model_name(); if(not it->get_kernel_info().empty()) { ss << it->get_kernel_info().to_string(); } if (not it->get_comment().empty()) { ss << " => " << it->get_comment(); } ss << 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