00001 /*!@file Component/ModelManager.C manages a model as collection of ModelComponents */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 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/Component/ModelManager.C $ 00035 // $Id: ModelManager.C 14253 2010-11-20 01:52:00Z rand $ 00036 // 00037 00038 #include "Component/ModelManager.H" 00039 00040 #include "Component/CmdlineOptionManager.H" 00041 #include "Component/GlobalOpts.H" 00042 #include "Component/ParamMap.H" 00043 #include "Util/AllocAux.H" 00044 #include "Util/CpuTimer.H" 00045 #include "Util/MathFunctions.H" 00046 #include "Util/fpe.H" 00047 #include "Util/fpu.H" 00048 #include "Util/log.H" 00049 #include "Util/terminate.H" 00050 #include "Util/version.H" 00051 #include "rutz/atomic.h" 00052 #include "rutz/demangle.h" 00053 #include "rutz/prof.h" 00054 00055 #include <cstdlib> // for getenv() 00056 #include <iostream> 00057 #include <string> 00058 #include <typeinfo> 00059 #include <cstdio> // for fopen() 00060 00061 using std::cerr; 00062 using std::endl; 00063 using std::string; 00064 00065 // ############################################################## 00066 //! This is the internal implementation struct for ModelManager. 00067 /*! We use the implementation approach so that clients of ModelManager 00068 aren't exposed to its implementation details (and thus they don't 00069 have to recompile everytime something changes in ModelManager's 00070 implementation). */ 00071 struct ModelManager::Impl 00072 { 00073 Impl(ModelManager* owner) 00074 : 00075 paramShowHelpMsg(&OPT_ShowHelpMessage, owner), 00076 paramShowVersion(&OPT_ShowVersion, owner), 00077 paramShowSvnVersion(&OPT_ShowSvnVersion, owner), 00078 paramCheckPristine(&OPT_CheckPristine, owner), 00079 paramDebugMode(&OPT_DebugMode, owner), 00080 paramUsingFPE(&OPT_UsingFPE, owner), 00081 paramFpuPrecision(&OPT_FpuPrecision, owner), 00082 paramFpuRoundingMode(&OPT_FpuRoundingMode, owner), 00083 paramTestMode(&OPT_TestMode, owner), 00084 paramProfileFile(&OPT_ProfileOutFile, owner), 00085 paramLogVerb(&OPT_LogVerb, owner), 00086 paramEchoArgs(&OPT_EchoArgs, owner), 00087 paramMemCaching(&OPT_MemCaching, owner), 00088 userLogVerb(MYLOGVERB) 00089 { 00090 // WARNING! Don't call any code here; instead call code from 00091 // ModelManager's constructor. That's because if we call any code 00092 // here that ends up back in some other ModelManager function, the 00093 // rep will not yet be initialized -- it will be null or garbage 00094 // -- since we haven't yet returned from the Impl constructor. 00095 } 00096 00097 CmdlineOptionManager com; 00098 00099 OModelParam<bool> paramShowHelpMsg; //!< print help message? 00100 OModelParam<bool> paramShowVersion; //!< print full version info? 00101 OModelParam<bool> paramShowSvnVersion;//!< print svn repo version? 00102 OModelParam<bool> paramCheckPristine; //!< check if the source is pristine? 00103 OModelParam<bool> paramDebugMode; //!< use debug mode? 00104 OModelParam<bool> paramUsingFPE; //!< use floating-point exceptions? 00105 OModelParam<FpuPrecision> paramFpuPrecision; //!< floating-point precision 00106 OModelParam<FpuRoundingMode> paramFpuRoundingMode; //!< floating-point rounding mode 00107 OModelParam<bool> paramTestMode; //!< use test mode? 00108 OModelParam<string> paramProfileFile; //!< Where to save profiling information 00109 rutz::shared_ptr<OModelParam<string> > paramLoadConfigFname; //!< Name of a config file to load up 00110 rutz::shared_ptr<OModelParam<string> > paramSaveConfigFname; //!< Name of a config file to save to 00111 OModelParam<string> paramLogVerb; //!< Log verbosity level 00112 OModelParam<bool> paramEchoArgs; //!< echo command-line args during start()? 00113 OModelParam<bool> paramMemCaching; 00114 00115 bool autoLoadConfig; //!< Load ~/.execname just before parsing command-line 00116 00117 bool didSave; //!< was saveConfig() already called? 00118 00119 const int userLogVerb; //!< the log verbosity level set by the user before the ModelManager was created 00120 00121 CpuTimer timer; 00122 }; 00123 00124 00125 // ############################################################## 00126 // ############################################################## 00127 // ModelManager member functions 00128 // ############################################################## 00129 // ############################################################## 00130 00131 // ############################################################## 00132 ModelManager::ModelManager(const string& descrName, 00133 const string& tag, 00134 const bool loadCfgOpt, 00135 const bool saveCfgOpt, 00136 const bool autoLoadCfg) : 00137 ModelComponent(descrName, tag), 00138 rep(new Impl(this)) 00139 { 00140 // install a fancy termination handler that will print a backtrace 00141 invt_install_fancy_terminate(); 00142 00143 this->setManager(rep->com); 00144 00145 // NOTE no need to do explicit requestOption() here anymore; 00146 // instead, requestOption() during ModelComponent's implementation 00147 // of exportOptions() -- nevertheless, request the debug mode option 00148 // right away so that we aren't needlessly noisy at the beginning of 00149 // the program run: 00150 this->requestOption(rep->paramDebugMode); 00151 00152 // do we want an option to load a config file? 00153 if (loadCfgOpt) { 00154 rep->paramLoadConfigFname = 00155 OModelParam<string>::make(&OPT_LoadConfigFile, this); 00156 } 00157 00158 // do we want an option to save a config file? 00159 if (saveCfgOpt) { 00160 rep->paramSaveConfigFname = 00161 OModelParam<string>::make(&OPT_SaveConfigFile, this); 00162 } 00163 00164 // keep track of autoload: 00165 rep->autoLoadConfig = autoLoadCfg; 00166 00167 // keep track of whether saveConfig() has been called: 00168 rep->didSave = false; 00169 00170 // pick up settings from relevant environment variables now, before 00171 // the command-line is parsed, so that command-line options can 00172 // override the environment variables -- NOTE that if this becomes a 00173 // commonly-used idiom, then it might make sense to add a new 00174 // setOptionFromEnvironment() virtual function to OptionManager, and 00175 // implement it here in ModelManager 00176 const char* precision = getenv("INVT_FPU_PRECISION"); 00177 00178 if (precision != 0) 00179 { 00180 this->setOptionValString(rep->paramFpuPrecision.getOptionDef(), 00181 precision); 00182 } 00183 00184 const char* rounding = getenv("INVT_FPU_ROUNDING_MODE"); 00185 00186 if (rounding != 0) 00187 { 00188 this->setOptionValString(rep->paramFpuRoundingMode.getOptionDef(), 00189 rounding); 00190 } 00191 } 00192 00193 // ############################################################## 00194 ModelManager::~ModelManager() 00195 { 00196 if (this->started()) 00197 this->stop(); 00198 00199 // NOTE: one could be tempted to call saveConfig() here for 00200 // automatic persistence of our ModelParam values. But that would be 00201 // dangerous as some of our ModelComponents may already have been 00202 // destroyed by the time we get here. So, saveConfig() should be 00203 // called manually, at a point in the code where all ModelComponents 00204 // are still alive. 00205 00206 // let our components know that we are gone: 00207 managerDestroyed(); 00208 00209 delete rep; 00210 00211 // ugly const_cast to set rep=0 here, but the ugliness is justified 00212 // the fact that it allows us to ASSERT(rep!=0) in our other 00213 // functions to make sure that people don't try to use us after we 00214 // have already been destroyed 00215 *(const_cast<Impl**>(&rep)) = 0; 00216 } 00217 00218 // ############################################################## 00219 void ModelManager::allowOptions(const int mask) 00220 { 00221 ASSERT(rep != 0); 00222 rep->com.allowOptions(mask); 00223 } 00224 00225 // ############################################################## 00226 void ModelManager::requestOption(OptionedModelParam& p, 00227 const bool useMyVal) 00228 { 00229 ASSERT(rep != 0); 00230 rep->com.requestOption(p, useMyVal); 00231 } 00232 00233 // ############################################################## 00234 void ModelManager::unRequestOption(OptionedModelParam& p) 00235 { 00236 if (rep == 0) 00237 LERROR("Oops, it looks like some ModelComponent is trying " 00238 "to unrequest an OptionedModelParam during its " 00239 "destructor, but doesn't know that the ModelManager " 00240 "has already been destroyed. A likely cause of this " 00241 "is that the ModelComponent in question was never " 00242 "passed to addSubComponent()."); 00243 ASSERT(rep != 0); 00244 rep->com.unRequestOption(p); 00245 } 00246 00247 // ############################################################## 00248 void ModelManager::requestOptionAlias(const ModelOptionDef* def) 00249 { 00250 ASSERT(rep != 0); 00251 rep->com.requestOptionAlias(def); 00252 } 00253 00254 // ############################################################## 00255 void ModelManager::setOptionValString(const ModelOptionDef* def, 00256 const string& val) 00257 { 00258 ASSERT(rep != 0); 00259 rep->com.setOptionValString(def, val); 00260 } 00261 00262 // ############################################################## 00263 string ModelManager::getOptionValString(const ModelOptionDef* def) 00264 { 00265 ASSERT(rep != 0); 00266 return rep->com.getOptionValString(def); 00267 } 00268 00269 // ############################################################## 00270 bool ModelManager::isOptionRequested(const ModelOptionDef* def) const 00271 { 00272 ASSERT(rep != 0); 00273 return rep->com.isOptionRequested(def); 00274 } 00275 00276 // ############################################################## 00277 bool ModelManager::parseCommandLine(const int argc, 00278 const char** argv, 00279 const char* usage, 00280 const int minarg, 00281 const int maxarg) 00282 { 00283 ASSERT(rep != 0); 00284 00285 // export options if that hasn't been done already 00286 if (this->hasBeenExported() == false) 00287 exportOptions(MC_RECURSE); 00288 00289 // let's get our application name: 00290 if (argc <= 0) 00291 LFATAL("expected argc >= 1, got argc=%d", argc); 00292 string procname(argv[0]); 00293 uint ii = procname.rfind('/'); // skip the path; get just the filename: 00294 if (ii < procname.size()) procname = procname.substr(ii + 1); 00295 00296 // if we wanted to automatically load a config from ~/.execname, 00297 // let's do that now: 00298 if (rep->autoLoadConfig && getenv("HOME")) 00299 { 00300 string fname = string(getenv("HOME")) + "/." + procname; 00301 FILE* tryit = fopen(fname.c_str(), "r"); 00302 if (tryit) { // config file exists; let's load it: 00303 fclose(tryit); 00304 LINFO("Autoloading configuration from '%s'", fname.c_str()); 00305 ParamMap pmap; pmap.load(fname.c_str()); 00306 readParamsFrom(pmap); 00307 } 00308 } 00309 00310 return rep->com.parseCommandLine(argc, argv, usage, minarg, maxarg); 00311 } 00312 00313 // ############################################################## 00314 bool ModelManager::parseCommandLine(const int argc, 00315 char* const* argv, 00316 const char* usage, 00317 const int minarg, 00318 const int maxarg) 00319 { 00320 std::vector<const char*> argv2; 00321 while (*argv != 0) 00322 argv2.push_back(*argv++); 00323 argv2.push_back(0); 00324 00325 ASSERT(int(argv2.size()) == (argc + 1)); 00326 00327 return this->parseCommandLine(argc, &argv2[0], usage, minarg, maxarg); 00328 } 00329 00330 // ############################################################## 00331 bool ModelManager::parseCommandLineCore(const int argc, const char** argv) 00332 { 00333 ASSERT(rep != 0); 00334 return rep->com.parseCommandLineCore(argc, argv); 00335 } 00336 00337 // ############################################################## 00338 bool ModelManager::parseCommandLineCore(const char* args) 00339 { 00340 ASSERT(rep != 0); 00341 return rep->com.parseCommandLineCore(args); 00342 } 00343 00344 // ############################################################## 00345 uint ModelManager::numExtraArgs() const 00346 { 00347 ASSERT(rep != 0); 00348 return rep->com.numExtraArgs(); 00349 } 00350 00351 // ############################################################## 00352 string ModelManager::getExtraArg(const uint num) const 00353 { 00354 ASSERT(rep != 0); 00355 return rep->com.getExtraArg(num); 00356 } 00357 00358 // ############################################################## 00359 uint ModelManager::numOptionDefs() const 00360 { 00361 ASSERT(rep != 0); 00362 return rep->com.numOptionDefs(); 00363 } 00364 00365 // ############################################################## 00366 uint ModelManager::getOptionDefs(const ModelOptionDef** arr, uint narr) 00367 { 00368 ASSERT(rep != 0); 00369 return rep->com.getOptionDefs(arr, narr); 00370 } 00371 00372 // ############################################################## 00373 const ModelOptionDef* ModelManager::findOptionDef(const char* name) const 00374 { 00375 return rep->com.findOptionDef(name); 00376 } 00377 00378 // ############################################################## 00379 bool ModelManager::isOptionDefUsed(const ModelOptionDef* def) const 00380 { 00381 ASSERT(rep != 0); 00382 return rep->com.isOptionDefUsed(def); 00383 } 00384 00385 // ############################################################## 00386 void ModelManager::loadConfig() 00387 { 00388 ASSERT(rep != 0); 00389 if (rep->paramLoadConfigFname.get() != 0 && 00390 rep->paramLoadConfigFname->getVal().empty() == false) 00391 this->loadConfig(rep->paramLoadConfigFname->getVal()); 00392 } 00393 00394 // ############################################################## 00395 void ModelManager::loadConfig(const string& fname) 00396 { 00397 LINFO("Loading configuration from '%s'", fname.c_str()); 00398 ParamMap pmap; pmap.load(fname.c_str()); 00399 this->readParamsFrom(pmap); 00400 } 00401 00402 // ############################################################## 00403 void ModelManager::saveConfig() const 00404 { 00405 ASSERT(rep != 0); 00406 if (rep->paramSaveConfigFname.get() != 0 && 00407 rep->paramSaveConfigFname->getVal().empty() == false) 00408 this->saveConfig(rep->paramSaveConfigFname->getVal()); 00409 } 00410 00411 // ############################################################## 00412 void ModelManager::saveConfig(const string& fname) const 00413 { 00414 LINFO("Saving configuration to '%s'", fname.c_str()); 00415 ParamMap pmap; this->writeParamsTo(pmap); 00416 pmap.format(fname); 00417 } 00418 00419 // ############################################################## 00420 void ModelManager::start1() 00421 { 00422 ASSERT(rep != 0); 00423 00424 // echo the command-line if the user requested that: 00425 if (rep->paramEchoArgs.getVal()) 00426 { 00427 for (uint i = 0; i < rep->com.numArgs(); ++i) 00428 LINFO("argv[%u]='%s'", i, rep->com.getArg(i).c_str()); 00429 } 00430 00431 // report a bunch of settings: 00432 LINFO("Debug: %s, FPE: %s, FpuPrecision: %s, FpuRounding: %s, " 00433 "TestMode: %s, AtomicIntType: %s", 00434 rep->paramDebugMode.getVal() ? "ON" : "OFF", 00435 rep->paramUsingFPE.getVal() ? "ON" : "OFF", 00436 convertToString(getFpuPrecision()).c_str(), 00437 convertToString(getFpuRoundingMode()).c_str(), 00438 rep->paramTestMode.getVal() ? "ON" : "OFF", 00439 rutz::demangled_name(typeid(rutz::atomic_int_t))); 00440 00441 // did we want a debug printout? 00442 if (rep->paramDebugMode.getVal()) { 00443 std::cerr<<"==================== MODEL PARAMETERS ====================\n"; 00444 printout(std::cerr); 00445 std::cerr<<"==========================================================\n"; 00446 } 00447 00448 // if saveConfig() has not been called yet, let's do it now just 00449 // before we start all our components: 00450 if (rep->didSave == false) { rep->didSave = true; saveConfig(); } 00451 } 00452 00453 // ############################################################## 00454 void ModelManager::start2() 00455 { 00456 ASSERT(rep != 0); 00457 00458 rep->timer.reset(); 00459 } 00460 00461 // ############################################################## 00462 void ModelManager::stop1() 00463 { 00464 ASSERT(rep != 0); 00465 00466 rep->timer.mark(); 00467 rep->timer.report("from start() to stop()"); 00468 } 00469 00470 // ############################################################## 00471 void ModelManager::paramChanged(ModelParamBase* const param, 00472 const bool valueChanged, 00473 ParamClient::ChangeStatus* status) 00474 { 00475 ASSERT(rep != 0); 00476 00477 ModelComponent::paramChanged(param, valueChanged, status); 00478 00479 // change log verbosity level? 00480 if (param == &rep->paramLogVerb) { 00481 string v = rep->paramLogVerb.getVal(); 00482 00483 const int oldLogVerb = MYLOGVERB; 00484 00485 if (v.compare("Debug") == 0) MYLOGVERB = LOG_DEBUG; 00486 else if (v.compare("Info") == 0) MYLOGVERB = LOG_INFO; 00487 else if (v.compare("Error") == 0) MYLOGVERB = LOG_ERR; 00488 else if (v.compare("Fatal") == 0) MYLOGVERB = LOG_CRIT; 00489 else if (v.compare("Default") == 0) MYLOGVERB = rep->userLogVerb; 00490 else 00491 LFATAL("Invalid log verbosity value '%s' (valid are: " 00492 "[Debug|Info|Error|Fatal|Default])", v.c_str()); 00493 00494 if (MYLOGVERB != oldLogVerb) 00495 LERROR("Switching log verbosity to %s", v.c_str()); 00496 } 00497 00498 // show full version info? 00499 if (param == &rep->paramShowVersion) { 00500 if (rep->paramShowVersion.getVal()) { 00501 // print the version to stdout and exit 00502 fprintf(stdout, "%s\n", fullversion()); 00503 exit(0); 00504 } 00505 } 00506 00507 // show svn repo version? 00508 else if (param == &rep->paramShowSvnVersion) { 00509 if (rep->paramShowSvnVersion.getVal()) { 00510 // print the version to stdout and exit 00511 fprintf(stdout, "%s\n", svnversion()); 00512 exit(0); 00513 } 00514 } 00515 00516 // check if the source is pristine? 00517 else if (param == &rep->paramCheckPristine) { 00518 if (rep->paramCheckPristine.getVal()) { 00519 exit(isSourcePristine() ? 0 : 1); 00520 } 00521 } 00522 00523 // debug mode on/off? 00524 else if (param == &rep->paramDebugMode) { 00525 if (rep->paramDebugMode.getVal()) MYLOGVERB = LOG_DEBUG; 00526 else MYLOGVERB = rep->userLogVerb; 00527 } 00528 00529 // floating-point exceptions on/off? 00530 else if (param == &rep->paramUsingFPE && valueChanged) { 00531 if (rep->paramUsingFPE.getVal()) fpExceptionsOn(); 00532 else fpExceptionsOff(); 00533 } 00534 00535 // floating-point precision? 00536 else if (param == &rep->paramFpuPrecision) { 00537 setFpuPrecision(rep->paramFpuPrecision.getVal()); 00538 } 00539 00540 // floating-point rounding mode? 00541 else if (param == &rep->paramFpuRoundingMode) { 00542 setFpuRoundingMode(rep->paramFpuRoundingMode.getVal()); 00543 } 00544 00545 // test mode on/off? 00546 else if (param == &rep->paramTestMode) { 00547 if (rep->paramTestMode.getVal()) { 00548 // will produce deterministic pseudo-random sequences 00549 initRandomNumbersZero(); 00550 setOptionValString(&OPT_UseRandom, "false"); 00551 } else { 00552 initRandomNumbers(); 00553 setOptionValString(&OPT_UseRandom, "true"); 00554 } 00555 } 00556 00557 // save profiling information? 00558 else if (param == &rep->paramProfileFile) { 00559 // NOTE: we require an explicit "none" instead of just the empty 00560 // string to request no profiling output -- that way, if certain 00561 // programs want to set up their own default location for the 00562 // profile file, then we won't accidentally mess up their default 00563 // with an empty string. 00564 if (rep->paramProfileFile.getVal().compare("none") == 0) 00565 { 00566 rutz::prof::print_at_exit(false); 00567 } 00568 else if (rep->paramProfileFile.getVal().empty()) 00569 { 00570 // do nothing if it's an empty string, just leave things as 00571 // they are 00572 } 00573 else 00574 { 00575 rutz::prof::print_at_exit(true); 00576 rutz::prof::prof_summary_file_name 00577 (rep->paramProfileFile.getVal().c_str()); 00578 00579 // NOTE: we could also have a command-line option to control 00580 // whether the timing mode is RUSAGE (i.e. cpu usage) or 00581 // WALLCLOCK (i.e., real elapsed time) 00582 rutz::prof::set_timing_mode(rutz::prof::RUSAGE); 00583 } 00584 } 00585 00586 else if (param == rep->paramLoadConfigFname.get()) 00587 { 00588 // if processing this option just changed our loadConfigFile 00589 // parameter, that means that we just parsed an option that 00590 // specified that value. Let's load up the file immediately: 00591 loadConfig(); 00592 } 00593 00594 else if (param == &rep->paramMemCaching) 00595 { 00596 invt_allocation_allow_caching(rep->paramMemCaching.getVal()); 00597 } 00598 } 00599 00600 // ############################################################## 00601 bool ModelManager::debugMode() const 00602 { 00603 ASSERT(rep != 0); 00604 return rep->paramDebugMode.getVal(); 00605 } 00606 00607 // ############################################################## 00608 void ModelManager::setFPE(bool val) 00609 { 00610 ASSERT(rep != 0); 00611 rep->paramUsingFPE.setVal(val); 00612 } 00613 00614 // ############################################################## 00615 void ModelManager::clearExtraArgs() 00616 { 00617 ASSERT(rep != 0); 00618 rep->com.clearExtraArgs(); 00619 } 00620 00621 // ############################################################## 00622 void ModelManager::unRequestTestMode() 00623 { unRequestOption(rep->paramTestMode); } 00624 00625 // ############################################################## 00626 void ModelManager::unRequestUsingFPE() 00627 { unRequestOption(rep->paramUsingFPE); } 00628 00629 // ############################################################## 00630 /* So things look consistent in everyone's emacs... */ 00631 /* Local Variables: */ 00632 /* indent-tabs-mode: nil */ 00633 /* End: */