LoMetrics.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:05:44 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3