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: */