00001 /*!@file Simulation/SimEventQueue.C Dispatch simulation events */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Simulation/SimEventQueue.C $ 00035 // $Id: SimEventQueue.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "Simulation/SimEventQueue.H" 00039 00040 #include "Component/ModelOptionDef.H" 00041 #include "Component/GlobalOpts.H" 00042 #include "Simulation/SimEvents.H" 00043 #include "Simulation/SimulationOpts.H" 00044 #include "Util/AllocAux.H" 00045 #include "Util/sformat.H" 00046 #include "Util/TextLog.H" 00047 00048 #include <cstdio> 00049 00050 static const ModelOptionDef OPT_ShowMemStats = 00051 { MODOPT_FLAG, "ShowMemStats", &MOC_GENERAL, OPTEXP_CORE, 00052 "Show verbose memory allocation statistics.", 00053 "mem-stats", '\0', "", "false" }; 00054 00055 static const ModelOptionDef OPT_ShowMemStatsUnits = 00056 { MODOPT_ARG(size_t), "ShowMemStatsUnits", &MOC_GENERAL, OPTEXP_CORE, 00057 "Allocation unit size (in bytes) to use when displaying the " 00058 "verbose memory statistics, or 0 to let simulation modules decide " 00059 "on an allocation unit each time they request that stats be shown.", 00060 "mem-stats-units", '\0', "<bytes>", "0" }; 00061 00062 // ###################################################################### 00063 SimEventQueue::SimEventQueue(OptionManager& mgr, 00064 const std::string& descrName, 00065 const std::string& tagName, 00066 const SimTime starttime) : 00067 SimModule(mgr, descrName, tagName), 00068 itsTimeStep(&OPT_SimulationTimeStep, this), 00069 itsTooMuchTime(&OPT_SimulationTooMuchTime, this), 00070 itsShowMemStats(&OPT_ShowMemStats, this), 00071 itsShowMemStatsUnits(&OPT_ShowMemStatsUnits, this), 00072 itsLogFile(&OPT_TextLogFile, this), 00073 t(starttime), itsQueue() 00074 { } 00075 00076 // ###################################################################### 00077 SimEventQueue::~SimEventQueue() 00078 { } 00079 00080 // ###################################################################### 00081 void SimEventQueue::start1() 00082 { 00083 SimModule::start1(); 00084 00085 // make sure the realm in which we are exists, since we will be 00086 // posting events into it (e.g., SimEventClockTick), even if nobody 00087 // is going to catch them and hence that realm might not have been 00088 // created yet: 00089 getRealm(realm(), true); 00090 } 00091 00092 // ###################################################################### 00093 void SimEventQueue::evolve(SimEventQueue& q) 00094 { 00095 LFATAL("Never call this function!"); 00096 } 00097 00098 // ###################################################################### 00099 SimStatus SimEventQueue::evolve() 00100 { 00101 // our clock is ticking! Let everyone know: 00102 rutz::shared_ptr<SimEventClockTick> ee(new SimEventClockTick(this, now())); 00103 post(ee); 00104 00105 // did anyone request that we show memory stats? 00106 if (itsShowMemStats.getVal()) 00107 { 00108 if (SeC<SimEventShowMemStats> e = check<SimEventShowMemStats>(this)) 00109 { 00110 LINFO("##### %s #####", e->toString().c_str()); 00111 00112 // gobble up all other requests. NOTE: if several requests had 00113 // different units we only show the first one. Maybe a FIXME: 00114 while (SeC<SimEventShowMemStats> ee = check<SimEventShowMemStats>(this)) 00115 LINFO("##### %s #####", ee->toString().c_str()); 00116 00117 showMemStats(e->frame(), e->unit()); 00118 } 00119 } 00120 00121 // did anyone post a userwait event? 00122 if (SeC<SimEventUserWait> e = check<SimEventUserWait>(this)) 00123 { 00124 // make sure we only pause once even though several modules may 00125 // have requested a pause: 00126 do { 00127 LINFO("##### %s #####", e->toString().c_str()); 00128 e = check<SimEventUserWait>(this); 00129 } while(e); 00130 00131 printf("<<<<< Press [RETURN] to continue >>>>>\n"); 00132 char tmp[10]; 00133 char* ret = fgets(tmp, 10, stdin); 00134 if (ret); 00135 } 00136 00137 // did anyone post a break event? 00138 if (SeC<SimEventBreak> e = check<SimEventBreak>(this)) 00139 { 00140 // make sure we report all break requests: 00141 do { 00142 LINFO("##### %s #####", e->toString().c_str()); 00143 e = check<SimEventBreak>(this); 00144 } while(e); 00145 00146 LINFO("##### Break requested -- DONE #####"); 00147 showMemStats(-2, 0); 00148 return SIM_BREAK; 00149 } 00150 00151 // have we run for too long? 00152 if (t > itsTooMuchTime.getVal()) 00153 { 00154 LINFO("#### Too much time elapsed -- DONE ####"); 00155 showMemStats(-2, 0); 00156 return SIM_BREAK; 00157 } 00158 00159 // increment t by one step: 00160 t += itsTimeStep.getVal(); 00161 00162 // let our TextLog know about the new time: 00163 setLogTime(itsLogFile.getVal(), t); 00164 00165 // keep running... 00166 return SIM_CONTINUE; 00167 } 00168 00169 // ###################################################################### 00170 void SimEventQueue::clear() 00171 { 00172 SeqData::iterator itr = itsQueue.begin(), stop = itsQueue.end(); 00173 while (itr != stop) { 00174 RealmData *rd = &(itr->second); 00175 SeqEntryVec *seq = &(rd->events); 00176 seq->clear(); 00177 ++itr; 00178 } 00179 } 00180 00181 // ###################################################################### 00182 void SimEventQueue::prune(const SimTime& tt) 00183 { 00184 SeqData::iterator itr = itsQueue.begin(), stop = itsQueue.end(); 00185 while (itr != stop) { 00186 RealmData *rd = &(itr->second); 00187 SeqEntryVec *seq = &(rd->events); 00188 00189 // delete all events that are <= tt: 00190 SeqEntryVec::iterator ee = seq->begin(); 00191 while (ee != seq->end()) if (ee->first <= tt) ee = seq->erase(ee); else ++ee; 00192 00193 ++itr; 00194 } 00195 } 00196 00197 // ###################################################################### 00198 const SimTime& SimEventQueue::now() const 00199 { return t; } 00200 00201 // ###################################################################### 00202 void SimEventQueue::resetTime(const SimTime& tim) 00203 { 00204 this->clear(); 00205 t = tim; 00206 } 00207 // ###################################################################### 00208 SimEventQueue::RealmData* SimEventQueue::getRealm(const std::string& realmname, const bool create_on_fail) 00209 { 00210 // do we already know about thsi realm? 00211 SeqData::iterator itr = itsQueue.find(realmname); 00212 if (itr == itsQueue.end()) 00213 { 00214 if (create_on_fail) 00215 { 00216 // first time we encounter this realm, let's create an entry for it: 00217 RealmData rd; 00218 std::pair<SeqData::iterator, bool> ii = itsQueue.insert(SeqData::value_type(realmname, rd)); 00219 if (ii.second == false) LFATAL("Error creating realm [%s]", realmname.c_str()); 00220 itr = ii.first; // use that new entry in the rest of this function 00221 } 00222 else 00223 LFATAL("Unknown realm [%s]", realmname.c_str()); 00224 } 00225 00226 return &(itr->second); 00227 } 00228 00229 // ###################################################################### 00230 void SimEventQueue::registerSimCallbackClient(SimModule *s) 00231 { 00232 // get the realm, create it if new: 00233 SimEventQueue::RealmData *rd = getRealm(s->realm(), true); 00234 00235 // get the callback map for this realm: 00236 scbm *themap = &(rd->callbacks); 00237 00238 // loop over all of the client's callbacks and register them: 00239 typedef std::vector<SimCallbackBase *> vscbb; 00240 vscbb *v = &(s->itsSimCallbacks); 00241 vscbb::const_iterator c = v->begin(), stop = v->end(); 00242 while (c != stop) { 00243 SimCallbackBase *cb = (*c); 00244 00245 // get the event type: 00246 const std::type_info *ti = &cb->etype(); 00247 00248 // do we already have registered callbacks for this event type? 00249 scbm::iterator i = themap->find(ti); 00250 00251 if (i == themap->end()) { 00252 // first time we encounter this event type, create a new map entry for it: 00253 rutz::shared_ptr<sscbb> newset(new sscbb()); 00254 std::pair<scbm::iterator, bool> ii = themap->insert(scbm::value_type(ti, newset)); 00255 if (ii.second == false) 00256 LFATAL("Error registering callback [%s] in realm [%s]", cb->toString().c_str(), s->realm().c_str()); 00257 i = ii.first; 00258 } 00259 00260 // add the callback to our set of callbacks for that event type: 00261 i->second->insert(cb); 00262 00263 LDEBUG("Registered [%s] in realm [%s]", cb->toString().c_str(), s->realm().c_str()); 00264 00265 ++c; 00266 } 00267 } 00268 00269 // ###################################################################### 00270 void SimEventQueue::registerSimReqHandlerClient(SimModule *s) 00271 { 00272 // get the realm, create it if new: 00273 SimEventQueue::RealmData *rd = getRealm(s->realm(), true); 00274 00275 // get the handlers map for this realm: 00276 srhm *themap = &(rd->reqhandlers); 00277 00278 // loop over all of the client's request handlers and register them: 00279 typedef std::vector<SimReqHandlerBase *> vsrhb; 00280 vsrhb *v = &(s->itsSimReqHandlers); 00281 vsrhb::const_iterator c = v->begin(), stop = v->end(); 00282 while (c != stop) { 00283 SimReqHandlerBase *cb = (*c); 00284 00285 // get the req type: 00286 const std::type_info *ti = &cb->rtype(); 00287 00288 // do we already have registered callbacks for this event type? 00289 srhm::iterator i = themap->find(ti); 00290 00291 if (i == themap->end()) { 00292 // first time we encounter this req type, create a new map entry for it: 00293 rutz::shared_ptr<ssrhb> newset(new ssrhb()); 00294 std::pair<srhm::iterator, bool> ii = themap->insert(srhm::value_type(ti, newset)); 00295 if (ii.second == false) 00296 LFATAL("Error registering handler [%s] in realm [%s]", cb->toString().c_str(), s->realm().c_str()); 00297 i = ii.first; 00298 } 00299 00300 // add the handler to our set of handlers for that req type: 00301 i->second->push_back(cb); 00302 00303 LDEBUG("Registered [%s] in realm [%s]", cb->toString().c_str(), s->realm().c_str()); 00304 00305 ++c; 00306 } 00307 } 00308 00309 // ###################################################################### 00310 void SimEventQueue::printCallbacks() const 00311 { 00312 SeqData::const_iterator itr = itsQueue.begin(), stop = itsQueue.end(); 00313 while (itr != stop) { 00314 const char *rname = itr->first.c_str(); 00315 const RealmData *rd = &(itr->second); 00316 const scbm *cmap = &(rd->callbacks); 00317 const srhm *rmap = &(rd->reqhandlers); 00318 00319 scbm::const_iterator c = cmap->begin(), sto = cmap->end(); 00320 while (c != sto) { 00321 rutz::shared_ptr<sscbb> s = c->second; 00322 sscbb::const_iterator i = s->begin(), fini = s->end(); 00323 while (i != fini) LINFO("[%s] %s", rname, (*i++)->toString().c_str()); 00324 ++c; 00325 } 00326 srhm::const_iterator cc = rmap->begin(), sstop = rmap->end(); 00327 while (cc != sstop) { 00328 rutz::shared_ptr<ssrhb> s = cc->second; 00329 ssrhb::const_iterator i = s->begin(), fini = s->end(); 00330 while (i != fini) LINFO("[%s] %s", rname, (*i++)->toString().c_str()); 00331 ++cc; 00332 } 00333 ++itr; 00334 } 00335 } 00336 00337 // ###################################################################### 00338 void SimEventQueue::reset1() 00339 { 00340 resetTime(); 00341 00342 // propagate to our base class: 00343 SimModule::reset1(); 00344 } 00345 00346 // ###################################################################### 00347 void SimEventQueue::showMemStats(const int frame, const size_t units) const 00348 { 00349 size_t u = itsShowMemStatsUnits.getVal(); 00350 if (u == 0) 00351 { 00352 if (units != 0) u = units; 00353 // else ... just leave u=0 so that invt_allocation_show_stats() 00354 // can fall back to whatever default value has been passed to 00355 // invt_allocation_set_stats_units() 00356 } 00357 00358 if (frame >= 0) 00359 { 00360 SHOWMEMORY("MEMORY USAGE: frame %d t=%.1fms", frame, t.msecs()); 00361 invt_allocation_show_stats 00362 (1, sformat("frame %06d", frame).c_str(), u); 00363 } 00364 else if (frame == -1) 00365 { 00366 SHOWMEMORY("MEMORY USAGE: t=%.1fms", t.msecs()); 00367 invt_allocation_show_stats(1, "", u); 00368 } 00369 else 00370 { 00371 SHOWMEMORY("FINAL MEMORY USAGE: t=%.1fms", t.msecs()); 00372 invt_allocation_show_stats(1, "final", u); 00373 } 00374 } 00375 00376 // ###################################################################### 00377 /* So things look consistent in everyone's emacs... */ 00378 /* Local Variables: */ 00379 /* mode: c++ */ 00380 /* indent-tabs-mode: nil */ 00381 /* End: */