00001 /** 00002 \file Robots/LoBot/control/LoMetrics.C 00003 \brief This file defines the static data members and non-inline member 00004 functions of the lobot::Metrics class. 00005 */ 00006 00007 // //////////////////////////////////////////////////////////////////// // 00008 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00009 // by the University of Southern California (USC) and the iLab at USC. // 00010 // See http://iLab.usc.edu for information about this project. // 00011 // //////////////////////////////////////////////////////////////////// // 00012 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00013 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00014 // in Visual Environments, and Applications'' by Christof Koch and // 00015 // Laurent Itti, California Institute of Technology, 2001 (patent // 00016 // pending; application number 09/912,225 filed July 23, 2001; see // 00017 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00018 // //////////////////////////////////////////////////////////////////// // 00019 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00022 // redistribute it and/or modify it under the terms of the GNU General // 00023 // Public License as published by the Free Software Foundation; either // 00024 // version 2 of the License, or (at your option) any later version. // 00025 // // 00026 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00027 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00028 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00029 // PURPOSE. See the GNU General Public License for more details. // 00030 // // 00031 // You should have received a copy of the GNU General Public License // 00032 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00033 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00034 // Boston, MA 02111-1307 USA. // 00035 // //////////////////////////////////////////////////////////////////// // 00036 // 00037 // Primary maintainer for this file: mviswana usc edu 00038 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/control/LoMetrics.C $ 00039 // $Id: LoMetrics.C 13838 2010-08-27 20:42:20Z mviswana $ 00040 // 00041 00042 //------------------------------ HEADERS -------------------------------- 00043 00044 // lobot headers 00045 #include "Robots/LoBot/control/LoMetrics.H" 00046 00047 #include "Robots/LoBot/LoApp.H" 00048 #include "Robots/LoBot/slam/LoMap.H" 00049 #include "Robots/LoBot/config/LoConfigHelpers.H" 00050 00051 #include "Robots/LoBot/misc/LoRegistry.H" 00052 #include "Robots/LoBot/misc/singleton.hh" 00053 #include "Robots/LoBot/util/LoTime.H" 00054 00055 // Standard C++ headers 00056 #include <fstream> 00057 #include <algorithm> 00058 #include <iterator> 00059 00060 // Standard C headers 00061 //#include <time.h> 00062 00063 //----------------------------- NAMESPACE ------------------------------- 00064 00065 namespace lobot { 00066 00067 //-------------------------- KNOB TWIDDLING ----------------------------- 00068 00069 namespace { 00070 00071 // Retrieve settings from vfh section of config file 00072 template<typename T> 00073 inline T conf(const std::string& key, const T& default_value) 00074 { 00075 return get_conf<T>(LOBE_METRICS, key, default_value) ; 00076 } 00077 00078 /// This local class encapsulates various parameters that can be used to 00079 /// tweak different aspects of the metrics behaviour. 00080 class Params : public singleton<Params> { 00081 /// This setting specifies the prefix of the file name to which the 00082 /// metrics should be written. By default, it is 00083 /// "/tmp/lobot-metrics-". 00084 /// 00085 /// The remainder of the metrics log file's name is generated using 00086 /// the current time in the format "yyyymmdd-HHMMSS". There is no file 00087 /// name extension. 00088 std::string m_log_file ; 00089 00090 /// The metrics behaviour buffers all the metrics related messages 00091 /// sent by other behaviours and, periodically, when the buffer is 00092 /// "full," dumps the buffer to the log file. This setting specifies 00093 /// the minimum number of messages that should be collected before the 00094 /// internal buffer will be written to disk and cleared. 00095 int m_dump_threshold ; 00096 00097 /// Most log messages begin with a small descriptive phrase such as 00098 /// "tracking pose" and are then followed by some values (such as the 00099 /// pose alluded to in the afore-mentioned phrase). To make the log 00100 /// more readable, all the opening phrases are written left-justified 00101 /// in a field width specified by this setting. 00102 int m_opening_width ; 00103 00104 /// The number of milliseconds between successive iterations of this 00105 /// behaviour. 00106 /// 00107 /// WARNING: The ability to change a behaviour's update frequency is a 00108 /// very powerful feature whose misuse or abuse can wreak havoc! Be 00109 /// sure to use reasonable values for this setting. 00110 int m_update_delay ; 00111 00112 /// Private constructor because this is a singleton. 00113 Params() ; 00114 friend class singleton<Params> ; 00115 00116 public: 00117 /// Accessing the various parameters 00118 //@{ 00119 static const std::string& log_file() {return instance().m_log_file ;} 00120 static int dump_threshold() {return instance().m_dump_threshold ;} 00121 static int opening_width() {return instance().m_opening_width ;} 00122 static int update_delay() {return instance().m_update_delay ;} 00123 //@} 00124 } ; 00125 00126 // Parameter initialization 00127 Params::Params() 00128 : m_log_file(conf<std::string>("log_prefix", "/tmp/lobot-metrics-") 00129 + startup_timestamp_str()), 00130 m_dump_threshold(clamp(conf("dump_threshold", 500), 100, 5000)), 00131 m_opening_width(clamp(conf("opening_phrase_width", 20), 16, 40)), 00132 m_update_delay(clamp(conf("update_delay", 2500), 750, 5000)) 00133 {} 00134 00135 } // end of anonymous local namespace encapsulating above helpers 00136 00137 //------------------------ STATIC DATA MEMBERS -------------------------- 00138 00139 // As explained in the header file, this class is not really a singleton, 00140 // but acts like one nonetheless. 00141 Metrics* Metrics::m_instance ; 00142 00143 //-------------------------- INITIALIZATION ----------------------------- 00144 00145 Metrics::Metrics() 00146 : base(Params::update_delay()) 00147 { 00148 m_instance = this ; 00149 start(LOBE_METRICS) ; 00150 } 00151 00152 // Before we start up, let's allocate enough memory for the messages 00153 // buffer. But no point wasting memory in case there are multiple 00154 // instances of this behaviour (should not really happen in practice). 00155 void Metrics::pre_run() 00156 { 00157 if (m_instance == this) { 00158 const int T = Params::dump_threshold() ; 00159 m_buffer.reserve(3*T/2) ; 00160 } 00161 } 00162 00163 //---------------------- THE BEHAVIOUR'S ACTION ------------------------- 00164 00165 // Quick helper to dump message buffer to log file 00166 static void dump(const std::vector<std::string>& messages) 00167 { 00168 std::ofstream log(Params::log_file().c_str(), 00169 std::ios::out | std::ios::app) ; 00170 std::copy(messages.begin(), messages.end(), 00171 std::ostream_iterator<std::string>(log, "\n")) ; 00172 } 00173 00174 // Periodically dump message buffer to log file 00175 void Metrics::action() 00176 { 00177 // Usually, there should be just one instance of the metrics 00178 // behaviour. But just in case the config file somehow asks for 00179 // multiple instances of this behaviour, we should double-check and 00180 // ignore the action methods for all but the "active" metrics 00181 // behaviour. There ought be no real harm in not performing this 00182 // short-circuit test; but no point executing useless code... 00183 if (m_instance != this) 00184 return ; 00185 00186 // Copy message buffer to avoid holding up other threads using the 00187 // metrics logging facility. 00188 std::vector<std::string> messages ; 00189 m_mutex.acquire() ; 00190 if (static_cast<int>(m_buffer.size()) >= Params::dump_threshold()) { 00191 std::copy(m_buffer.begin(), m_buffer.end(), 00192 std::back_inserter(messages)) ; 00193 m_buffer.clear() ; 00194 } 00195 m_mutex.release() ; 00196 dump(messages) ; 00197 } 00198 00199 //----------------------------- CLEAN-UP -------------------------------- 00200 00201 // When app is quitting, dump remaining messages in buffer to log. 00202 // 00203 // DEVNOTE: The destructor should be invoked from lobot::App::~App(). At 00204 // that point, all threads should be dead. Therefore, it should be safe 00205 // to use the buffer without the mutex. 00206 Metrics::~Metrics() 00207 { 00208 if (m_instance == this) { 00209 dump(m_buffer) ; 00210 m_instance = 0 ; 00211 } 00212 } 00213 00214 //---------------------------- PUBLIC API ------------------------------- 00215 00216 // Helper function for prefixing log messages with a time-stamp 00217 void Metrics::Log::ts() 00218 { 00219 str << current_time() << ' ' ; 00220 } 00221 00222 // Helper function for queuing log messages in the metrics behaviour's 00223 // internal message buffer. 00224 void Metrics::Log::send() 00225 { 00226 Metrics* M = Metrics::m_instance ; 00227 if (M) 00228 { 00229 AutoMutex m(M->m_mutex) ; 00230 M->m_buffer.push_back(str.str()) ; 00231 } 00232 } 00233 00234 // The current time is automatically recorded with every metric 00235 Metrics::Log::Log() 00236 : need_ts(true) 00237 {} 00238 00239 // When the local Metrics::Log object in the client function goes out of 00240 // scope, the message it has accumulated will be added to the Metrics 00241 // object's internal buffer. 00242 Metrics::Log::~Log() 00243 { 00244 send() ; 00245 } 00246 00247 // When clients want to "reuse" a local Metrics::Log object over and over 00248 // to create new messages, they should use a Metrics::endl manipulator to 00249 // end one message and begin another. 00250 Metrics::Log& operator<<(Metrics::Log& metlog, const Metrics::endl&) 00251 { 00252 metlog.send() ; 00253 metlog.str.str("") ; 00254 metlog.need_ts = true ; 00255 return metlog ; 00256 } 00257 00258 // To split a long message across multiple lines 00259 Metrics::Log& operator<<(Metrics::Log& metlog, const Metrics::newl&) 00260 { 00261 metlog.str << " \\\n " ; 00262 return metlog ; 00263 } 00264 00265 // Helper to return the opening phrase's field width for each log message 00266 int Metrics::opening_phrase_width() 00267 { 00268 return Params::opening_width() ; 00269 } 00270 00271 //----------------------------------------------------------------------- 00272 00273 } // end of namespace encapsulating this file's definitions 00274 00275 /* So things look consistent in everyone's emacs... */ 00276 /* Local Variables: */ 00277 /* indent-tabs-mode: nil */ 00278 /* End: */