LoMetrics.H

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/control/LoMetrics.H
00003    \brief A behaviour for collecting performance metrics.
00004 
00005    This file defines a class that implements a behaviour for gathering
00006    all sorts of useful data as lobot runs. For example, we can get
00007    information such as the robot's pose history, the time at which a goal
00008    is reached, average speed of the robot, number of emergency stop and
00009    extrication events, actual and predicted times-to-impact, and so on.
00010    All this data is periodically written to a log file, which can then be
00011    analyzed off-line.
00012 */
00013 
00014 // //////////////////////////////////////////////////////////////////// //
00015 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00016 // by the University of Southern California (USC) and the iLab at USC.  //
00017 // See http://iLab.usc.edu for information about this project.          //
00018 // //////////////////////////////////////////////////////////////////// //
00019 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00020 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00021 // in Visual Environments, and Applications'' by Christof Koch and      //
00022 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00023 // pending; application number 09/912,225 filed July 23, 2001; see      //
00024 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00025 // //////////////////////////////////////////////////////////////////// //
00026 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00027 //                                                                      //
00028 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00029 // redistribute it and/or modify it under the terms of the GNU General  //
00030 // Public License as published by the Free Software Foundation; either  //
00031 // version 2 of the License, or (at your option) any later version.     //
00032 //                                                                      //
00033 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00034 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00035 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00036 // PURPOSE.  See the GNU General Public License for more details.       //
00037 //                                                                      //
00038 // You should have received a copy of the GNU General Public License    //
00039 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00040 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00041 // Boston, MA 02111-1307 USA.                                           //
00042 // //////////////////////////////////////////////////////////////////// //
00043 //
00044 // Primary maintainer for this file: mviswana usc edu
00045 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/control/LoMetrics.H $
00046 // $Id: LoMetrics.H 13620 2010-06-25 05:12:03Z mviswana $
00047 //
00048 
00049 #ifndef LOBOT_METRICS_BEHAVIOUR_DOT_H
00050 #define LOBOT_METRICS_BEHAVIOUR_DOT_H
00051 
00052 //------------------------------ HEADERS --------------------------------
00053 
00054 // lobot headers
00055 #include "Robots/LoBot/control/LoBehavior.H"
00056 #include "Robots/LoBot/thread/LoMutex.H"
00057 #include "Robots/LoBot/misc/factory.hh"
00058 
00059 // Standard C++ headers
00060 #include <sstream>
00061 #include <string>
00062 #include <vector>
00063 
00064 //----------------------------- NAMESPACE -------------------------------
00065 
00066 namespace lobot {
00067 
00068 //------------------------- CLASS DEFINITION ----------------------------
00069 
00070 /**
00071    \class lobot::Metrics
00072    \brief A behaviour for gathering performance metrics about the robot.
00073 
00074    This class implements a behaviour that collects all sorts of useful
00075    data as lobot runs. For example, we can get information such as the
00076    robot's pose history, the time at which a goal is reached, average
00077    speed of the robot, number of emergency stop and extrication events,
00078    actual and predicted times-to-impact, and so on. All this data is
00079    periodically written to a log file, which can then be analyzed
00080    off-line.
00081 
00082    This behaviour does not control the robot in any way nor does it
00083    perform any sort of visualization.
00084 */
00085 class Metrics : public Behavior {
00086    // Prevent copy and assignment
00087    Metrics(const Metrics&) ;
00088    Metrics& operator=(const Metrics&) ;
00089 
00090    // Handy type to have around in a derived class
00091    typedef Behavior base ;
00092 
00093    // Boilerplate code to make the generic factory design pattern work
00094    friend  class subfactory<Metrics, base> ;
00095    typedef register_factory<Metrics, base> my_factory ;
00096    static  my_factory register_me ;
00097 
00098    /// Different behaviours report metrics using different data types.
00099    /// However, all of them get converted to strings and buffered by this
00100    /// class. When the buffer grows to some predefined limit, it will be
00101    /// written out to the log file.
00102    ///
00103    /// This data structure acts as the above-mentioned buffer of log
00104    /// messages.
00105    std::vector<std::string> m_buffer ;
00106 
00107    /// Since multiple behaviours can write to the above buffer, we need
00108    /// to synchronize accesses to it.
00109    Mutex m_mutex ;
00110 
00111    /// Although this class is not a singleton, it behaves like one. Its
00112    /// public interface consists of a helper class for building
00113    /// individual log messages, which then get buffered by the metrics
00114    /// behaviour. The above-mentioned helper class uses the following
00115    /// instance pointer to get to a Metrics object.
00116    ///
00117    /// DEVNOTE: We implement this behaviour in this way so that clients
00118    /// don't have to rely on the lobot::App object to get a suitable
00119    /// instance of this class and so that lobot::App doesn't have to
00120    /// implement a special API to search for this behaviour in its list
00121    /// of behaviours. Instead, client behaviours can simply use the
00122    /// logging API and let this class figure out how to get to a usable
00123    /// instance.
00124    ///
00125    /// DEVNOTE 2: Since the singleton concept is not enforced, users can,
00126    /// in fact, start multiple metrics behaviours. However, only one of
00127    /// them will be used, viz., the last one to be created; the others
00128    /// will simply waste CPU time and memory.
00129    static Metrics* m_instance ;
00130 
00131    /// A private constructor because behaviours are instantiated with an
00132    /// object factory and not directly by clients.
00133    Metrics() ;
00134 
00135    /// Some things to do before commencing regular action processing.
00136    void pre_run() ;
00137 
00138    /// This method checks if the message buffer has exceeded some
00139    /// preconfigured threshold and, if so, dumps it to the log.
00140    void action() ;
00141 
00142    /// Clean-up: dump any pending messages to log.
00143    ~Metrics() ;
00144 
00145    // Public interface for metrics logging
00146 public:
00147    /// This class defines a manipulator that can be used to end log
00148    /// entries and begin new ones. It is useful when we want to create an
00149    /// explicit instance of the Metrics::Log class (see below) and
00150    /// "reuse" that object for multiple log messages.
00151    struct endl {} ;
00152 
00153    /// This class defines a manipulator that can be used to break up long
00154    /// log entries over multiple lines. Each new line in an entry will be
00155    /// indented with eight spaces, while the previous ones end with a
00156    /// backslash. The first line in such a multiple line log entry will
00157    /// have a time-stamp prefix while the indented lines will not.
00158    struct newl {} ;
00159 
00160    /**
00161       \class lobot::Metrics::Log
00162       \brief A class for creating metrics related log messages and
00163       buffering them with the metrics behaviour for subsequent output to
00164       the log file.
00165 
00166       To create metrics related log messages, client behaviours should
00167       create a local instance of the Metrics::Log class and use the
00168       stream insertion operator to write messages to the metrics log
00169       file. The constructor of this class takes care of time-stamping
00170       each message and the destructor buffers the message with the
00171       Metrics behaviour. Here is the intended usage pattern for this
00172       class:
00173 
00174          void some_class::some_function()
00175          {
00176             Pose p = something_complicated() ;
00177             Metrics::Log() << "current pose: "
00178                            << p.x() << ' '
00179                            << p.y() << ' '
00180                            << p.t() ;
00181          }
00182 
00183       When the local Log object created in the chained operator<<
00184       statement goes out of scope, the message will be added to the
00185       Metrics behaviour's internal message buffer, which will then take
00186       care of periodically dumping all the messages to the log file.
00187 
00188       NOTE: It is not shown in the above example; however, clients may
00189       use I/O manipulators to get formatted output. But please don't end
00190       with newlines; those are added automatically when the message
00191       buffer is dumped to the log file.
00192 
00193       NOTE 2: To break up long lines, use the Metrics::newl "manipulator"
00194       like so:
00195 
00196          void some_class::some_function()
00197          {
00198             Metrics::Log() << "a fantastically long message that needs"
00199                            << Metrics::newl()
00200                            << "to be broken up across multiple lines" ;
00201          }
00202 
00203       The Metrics::newl manipulator will introduce a space followed by a
00204       backslash followed by a newline and then indent the next line in
00205       the log with eight spaces to indicate that this line is a
00206       continuation of the previous one.
00207 
00208       NOTE 3: Although the above examples illustrate using the metrics
00209       logging facility with an unnamed temporary object, it is also
00210       perfectly acceptable to explicitly create a Metrics::Log object and
00211       use it multiple times. However, keep in mind that all log messages
00212       will be treated as a single log entry and will show up on one line
00213       unless you use the Metrics::endl manipulator as shown below:
00214 
00215          void some_class::some_function()
00216          {
00217             Metrics::Log metlog ;
00218             metlog << "this is the first entry"  << Metrics::endl() ;
00219             metlog << "this is the second entry" << Metrics::endl() ;
00220             metlog << "oops, this and the next line" ;
00221             metlog << "are both part of the same log entry!" ;
00222          }
00223    */
00224    class Log {
00225       /// The metrics log messages are accumulated in an output string
00226       /// stream using the stream insertion operator. The destructor and
00227       /// the Metrics::endl manipulator will result in the contents of
00228       /// this string stream being buffered with the metrics behaviour.
00229       std::ostringstream str ;
00230 
00231       /// Each log entry will be automatically prefixed with a
00232       /// time-stamp. This flag keeps track of whether each use of the
00233       /// stream insertion operator requires a time-stamp to be output or
00234       /// not. When a Metrics::Log object is created, this flag will be
00235       /// initialized to true so that the very first operator<< results
00236       /// in a time-stamp. After that, this flag will be cleared so that
00237       /// subsequent uses of operator<< don't cause additional
00238       /// time-stamps.
00239       ///
00240       /// The Metrics::endl manipulator also results in setting this
00241       /// flag.
00242       bool need_ts ;
00243 
00244       /// A helper function to spit out a time-stamp.
00245       void ts() ;
00246 
00247       /// A helper function to send log messages to the metrics
00248       /// behaviour's internal message buffer.
00249       void send() ;
00250 
00251    public:
00252       /// When a Metrics::Log object is created, it will automatically
00253       /// cause a time-stamp to be prefixed to the message.
00254       Log() ;
00255 
00256       /// When a Metrics::Log object goes out of scope, it will queue the
00257       /// message with the metrics behaviour, which, in turn, will take
00258       /// care of periodically writing the messages to the log file.
00259       ~Log() ;
00260 
00261       /// The stream insertion operator for arbitrary data types.
00262       ///
00263       /// To create log entries, clients should instantiate the
00264       /// Metrics::Log class and "build" the full message by chaining
00265       /// multiple calls to this operator. When the Metrics::Log object
00266       /// goes out of scope, the message will be queued with the metrics
00267       /// behaviour.
00268       template<typename T> Log& operator<<(const T&) ;
00269 
00270       /// Conversion operator. This function converts Metrics::Log
00271       /// objects to std::ostringstream objects. This allows clients to
00272       /// simply reuse their operator<< definitions for std::ostream and
00273       /// not have to provide an overload for use with Metrics::Log.
00274       operator std::ostringstream&() {return str ;}
00275 
00276       // Dealing with the Metrics::endl and Metrics::newl manipulators
00277       friend Log& operator<<(Log&, const endl&) ;
00278       friend Log& operator<<(Log&, const newl&) ;
00279    } ;
00280 
00281    // Log objects will need to access the metrics behaviour's internal buffer
00282    friend class Log ;
00283 
00284    /// To make the metrics log more readable, each message's
00285    /// initial/opening phrase (such as "tracking pose" or "extricate") is
00286    /// left-justified within a field width specified in the config file.
00287    /// This helper function returns that setting.
00288    static int opening_phrase_width() ;
00289 
00290    /// A shorter alias for above function.
00291    static int opw() {return opening_phrase_width() ;}
00292 } ;
00293 
00294 //--------------------- TEMPLATE MEMBER FUNCTIONS -----------------------
00295 
00296 // Stream insertion operator for arbitrary data types. Client modules
00297 // need not define an operator<< for use especially with Metrics::Log
00298 // (though they may if they so wish). The Metrics::Log-to-std::ostream
00299 // conversion operator ensures that client modules that define an
00300 // operator<< for use with std::ostream will work unchanged in
00301 // conjunction with Metrics::Log.
00302 template<typename T>
00303 Metrics::Log& Metrics::Log::operator<<(const T& t)
00304 {
00305    if (need_ts) {
00306       ts() ;
00307       need_ts = false ;
00308    }
00309    str << t ;
00310    return *this ;
00311 }
00312 
00313 //----------------------- NON-MEMBER FUNCTIONS --------------------------
00314 
00315 /// This function ends a log entry and begins a new one. It is meant for
00316 /// use with Metrics::Log objects created explicitly so that they may be
00317 /// "reused" to output multiple log messages.
00318 Metrics::Log& operator<<(Metrics::Log&, const Metrics::endl&) ;
00319 
00320 /// This function breaks up long log entries into multiple lines by
00321 /// inserting a newline and indenting the next line of a multiple line
00322 /// log entry with two tabs.
00323 Metrics::Log& operator<<(Metrics::Log&, const Metrics::newl&) ;
00324 
00325 //-----------------------------------------------------------------------
00326 
00327 } // end of namespace encapsulating this file's definitions
00328 
00329 #endif
00330 
00331 /* So things look consistent in everyone's emacs... */
00332 /* Local Variables: */
00333 /* indent-tabs-mode: nil */
00334 /* End: */
Generated on Sun May 8 08:05:44 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3