/* ----------------------------------------------------------------------------- The copyright in this software is being made available under the Clear BSD License, included below. No patent rights, trademark rights and/or other Intellectual Property Rights other than the copyrights concerning the Software are granted under this license. The Clear BSD License Copyright (c) 2018-2023, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------------------- */ /** \file dtrace.cpp * \brief Implementation of trace messages support for debugging */ #include #include #include #include #include #include "CommonDef.h" #include "dtrace.h" namespace vvdec { void Channel::update( std::map< CType, int > state ) { for( std::list::iterator rules_iter = rule_list.begin(); rules_iter != rule_list.end(); ++rules_iter ) { /* iterate over conditions, get the state of the condition type * and check if contion is met: * if not -> go to next rule * yes -> go to next condition * if all conditions are met: set channel active and return */ bool probe = true; for( Rule::iterator cond_iter = rules_iter->begin(); cond_iter != rules_iter->end(); ++cond_iter ) { int sVal = state[cond_iter->type]; if( !cond_iter->eval( cond_iter->rval, sVal ) ) { probe = false; break; } } if( probe ) { _active = true; return; } } _active = false; } void Channel::add( std::vector rule ) { rule_list.push_back( rule ); } static inline std::vector &split( const std::string &s, char delim, std::vector &elems ) { std::stringstream ss( s ); std::string item; while ( std::getline( ss, item, delim ) ) { elems.push_back( item ); } return elems; } static inline std::vector split( const std::string &s, char delim ) { std::vector elems; split( s, delim, elems ); return elems; } CDTrace::CDTrace( const char *filename, const vstring& channel_names ) { if( filename ) m_trace_file = fopen( filename, "w" ); if( !m_trace_file ) { m_error_code = Error::FileOpenFailed; } int i = 0; for( vstring::const_iterator ci = channel_names.cbegin(); ci != channel_names.cend(); ++ci ) { deserializationTable[*ci] = i++; chanRules.push_back( Channel() ); } } CDTrace::CDTrace( const char *filename, const dtrace_channels_t& channels ) { if( filename ) m_trace_file = fopen( filename, "w" ); if( !m_trace_file ) { m_error_code = Error::FileOpenFailed; } for( dtrace_channels_t::const_iterator ci = channels.cbegin(); ci != channels.cend(); ++ci ) { deserializationTable[ci->channel_name] = ci->channel_number; chanRules.push_back( Channel() ); } } CDTrace::CDTrace( const std::string& sTracingFile, const std::string& sTracingRule, const dtrace_channels_t& channels ) : CDTrace( sTracingFile.c_str(), channels ) { if( !sTracingRule.empty() && m_error_code == Error::OK ) { m_error_code = addRule( sTracingRule ); } } CDTrace::CDTrace( const CDTrace& other ) { copy = true; m_trace_file = other.m_trace_file; chanRules = other.chanRules; condition_types = other.condition_types; state = other.state; deserializationTable = other.deserializationTable; m_error_code = other.m_error_code; } void CDTrace::swap( CDTrace& other ) { using std::swap; CDTrace& first = *this; CDTrace& second = other; swap(first.copy,second.copy); swap(first.m_trace_file,second.m_trace_file); swap(first.chanRules,second.chanRules); swap(first.condition_types,second.condition_types); swap(first.state,second.state); swap(first.deserializationTable,second.deserializationTable); } CDTrace& CDTrace::operator=( const CDTrace& other ) { CDTrace tmp(other); swap( tmp ); return *this; } CDTrace::~CDTrace() { if( !copy && m_trace_file ) fclose( m_trace_file ); } bool _cf_eq ( int bound, int val ) { return ( val==bound ); } bool _cf_neq( int bound, int val ) { return ( val!=bound ); } bool _cf_le ( int bound, int val ) { return ( val<=bound ); } bool _cf_ge ( int bound, int val ) { return ( val>=bound ); } CDTrace::Error CDTrace::addRule( std::string rulestring ) { vstring chans_conds = split( rulestring, ':' ); vstring channels = split( chans_conds[0], ',' ); vstring conditions = split( chans_conds[1], ',' ); /* parse the rules first */ std::vector rule; for( vstring::iterator ci = conditions.begin(); ci != conditions.end(); ++ci ) { /* find one of "==", "!=", "<=", ">=" */ const char *ops_[] = { "==", "!=", "<=", ">=" }; vstring operators( ops_,&ops_[sizeof( ops_ )/sizeof( ops_[0] )] ); vstring::iterator oi = operators.begin(); std::size_t pos = std::string::npos; do { if( ( pos = ci->find( *oi ) ) != std::string::npos ) break; } while( ++oi != operators.end() ); /* No operator found, malformed rules string -> abort */ if( pos == std::string::npos ) return Error::BadRule; CType ctype( *ci,0,pos ); int value = std::atoi( ci->substr( pos+2, ci->length()-( pos+2 ) ).c_str() ); //if( condition_types.find( ctype ) == condition_types.end() ) return 0; /* partially apply the condition value to the associated * condtion function and append it to the rule */ bool ( *cfunc )( int,int ); if( "==" == *oi ) cfunc = _cf_eq; else if( "!=" == *oi ) cfunc = _cf_neq; else if( "<=" == *oi ) cfunc = _cf_le; else if( ">=" == *oi ) cfunc = _cf_ge; else return Error::OK; // this is already taken care of rule.push_back( Condition( ctype, cfunc, value ) ); } /* add the rule to each channel */ for( vstring::iterator chan_iter = channels.begin(); chan_iter != channels.end(); ++chan_iter ) { std::map< Key, int>::iterator ichan = deserializationTable.find(*chan_iter); if( ichan != deserializationTable.end() ) chanRules[ichan->second].add( rule ); else return Error::UnknownChannel; } return Error::OK; } bool CDTrace::update( state_type stateval ) { state[stateval.first] = stateval.second; /* pass over all the channel rules */ for( std::vector< Channel >::iterator citer = chanRules.begin(); citer != chanRules.end(); ++citer ) { citer->update( state ); } return true; } void CDTrace::getChannelsList( std::string& sChannels ) { sChannels.clear(); /* pass over all the channel rules */ if( deserializationTable.size() > 0 ) { for( channel_map_t::iterator it = deserializationTable.begin(); it != deserializationTable.end(); ++it ) sChannels += it->first + "\n"; } } const char* CDTrace::getChannelName( int channel_number ) { static const char not_found[] = ""; if( deserializationTable.size() > 0 ) { for( channel_map_t::iterator it = deserializationTable.begin(); it != deserializationTable.end(); ++it ) if( it->second == channel_number ) return it->first.c_str(); } return not_found; } std::string CDTrace::getErrMessage() { std::string str = ""; if( m_error_code != Error::OK ) { if( m_error_code == Error::BadRule ) str = ( " - DTrace ERROR: Add tracing rule failed: DECERR_DTRACE_BAD_RULE" ); else if( m_error_code == Error::UnknownChannel ) str = ( " - DTrace ERROR: Add tracing rule failed: DECERR_DTRACE_UNKNOWN_CHANNEL" ); else if ( m_error_code == Error::FileOpenFailed ) str = ( " - DTrace ERROR: failed to open trace file" ); else { str = " - DTrace ERROR: Undefined error"; } } return str; } template< bool bCount> void CDTrace::dtrace( int k, const char *format, /*va_list args*/... ) { if( m_trace_file && chanRules[k].active() ) { va_list args; va_start ( args, format ); vfprintf ( m_trace_file, format, args ); fflush( m_trace_file ); va_end ( args ); if( bCount ) { chanRules[k].incrementCounter(); } } return; } template void CDTrace::dtrace( int k, const char *format, /*va_list args*/... ); template void CDTrace::dtrace( int k, const char *format, /*va_list args*/... ); void CDTrace::dtrace_repeat( int k, int i_times, const char *format, /*va_list args*/... ) { if( m_trace_file && chanRules[k].active() ) { va_list args; va_start( args, format ); while( i_times > 0 ) { i_times--; vfprintf( m_trace_file, format, args ); } fflush( m_trace_file ); va_end( args ); } return; } } // namespace vvdec