PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // plearn_main.cc 00004 // Copyright (C) 2002 Pascal Vincent 00005 // 00006 // Redistribution and use in source and binary forms, with or without 00007 // modification, are permitted provided that the following conditions are met: 00008 // 00009 // 1. Redistributions of source code must retain the above copyright 00010 // notice, this list of conditions and the following disclaimer. 00011 // 00012 // 2. Redistributions in binary form must reproduce the above copyright 00013 // notice, this list of conditions and the following disclaimer in the 00014 // documentation and/or other materials provided with the distribution. 00015 // 00016 // 3. The name of the authors may not be used to endorse or promote 00017 // products derived from this software without specific prior written 00018 // permission. 00019 // 00020 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00021 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00022 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00023 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00025 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00026 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00027 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00028 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 // 00031 // This file is part of the PLearn library. For more information on the PLearn 00032 // library, go to the PLearn Web site at www.plearn.org 00033 00034 00035 /* ******************************************************* 00036 * $Id: plearn_main.cc 10081 2009-04-03 17:43:08Z nouiz $ 00037 ******************************************************* */ 00038 00039 // From PLearn 00040 #include <plearn/base/RemoteDeclareMethod.h> 00041 #include "plearn_main.h" 00042 #include "PLearnCommandRegistry.h" 00043 #include <plearn/base/ProgressBar.h> 00044 #include <plearn/base/pl_repository_revision.h> 00045 #include <plearn/base/stringutils.h> 00046 #include <plearn/db/getDataSet.h> 00047 #include <plearn/io/fileutils.h> 00048 #include <plearn/io/pl_log.h> 00049 #include <plearn/math/random.h> 00050 #include <plearn/misc/Calendar.h> 00051 #include <plearn/misc/PLearnService.h> 00052 #include <plearn/vmat/VMat.h> 00053 #include <plearn/sys/Profiler.h> 00054 00055 // From C++ stdlib 00056 #include <exception> 00057 00058 #if USING_MPI 00059 #include <plearn/sys/PLMPI.h> 00060 #endif 00061 00062 #ifdef _OPENMP 00063 #include<omp.h> 00064 #endif 00065 00066 #ifndef WIN32 00067 #include <signal.h> 00068 #endif 00069 00070 namespace PLearn { 00071 using namespace std; 00072 00073 // Anonymous namespace to house version information 00074 namespace 00075 { 00076 int plearn_major_version; 00077 int plearn_minor_version; 00078 int plearn_fixlevel; 00079 } 00080 00081 void handler_of_interrup_signal (int sig){ 00082 PLERROR("We received an interrup signal!"); 00083 } 00084 //catch INTERRUP signal and throw an PLERROR. 00085 //We do this as some code catch PLERROR to do some cleanup. 00086 void catch_interrupt_signal(){ 00087 #ifndef WIN32 00088 struct sigaction my_action; 00089 my_action.sa_handler = handler_of_interrup_signal; 00090 my_action.sa_flags = SA_RESTART; 00091 sigaction (SIGINT, &my_action, NULL); 00092 #endif 00093 } 00094 00095 static bool is_command( string& possible_command ) 00096 { 00097 if(PLearnCommandRegistry::is_registered(possible_command)) 00098 return true; 00099 00100 if( isfile(possible_command) ) 00101 { 00102 possible_command = "run"; 00103 return false; 00104 } 00105 00106 PLERROR( "%s appears to neither be a known PLearn command, " 00107 "nor an existing .plearn script", possible_command.c_str() ); 00108 return false; 00109 } 00110 00111 static void output_version() 00112 { 00113 perr << version_string(); 00114 } 00115 00116 string version_string() 00117 { 00118 string s; 00119 if(plearn_major_version == -1) 00120 return string(); 00121 s = prgname() + ' ' + tostring(plearn_major_version); 00122 if (plearn_minor_version >= 0) { 00123 s += '.' + tostring(plearn_minor_version); 00124 if (plearn_fixlevel >= 0) 00125 s += '.' + tostring(plearn_fixlevel); 00126 } 00127 s += " svn_revision:" + pl_repository_revision(); 00128 s += " (" + pl_repository_compile_date() + ' ' + 00129 pl_repository_compile_time() + ")\n"; 00130 return s; 00131 } 00132 00133 void setVersion(int major_version, int minor_version, int fixlevel) 00134 { 00135 // Copy the version variables to private namespace (i.e. static variables) 00136 // to make them available to other callers. 00137 plearn_major_version = major_version; 00138 plearn_minor_version = minor_version; 00139 plearn_fixlevel = fixlevel; 00140 } 00141 00142 BEGIN_DECLARE_REMOTE_FUNCTIONS 00143 00144 declareFunction("versionString", &version_string, 00145 (BodyDoc("Returns PLearn version as a string.\n"), 00146 RetDoc ("version string"))); 00147 00148 END_DECLARE_REMOTE_FUNCTIONS 00149 00150 00151 static void set_global_calendars(string command_line_option) 00152 { 00153 // Assume command-line-option of the form 00154 // CalendarName1:CalendarFilename1,CalendarName2:CalendarFilename2,... 00155 vector<string> names_files = split(command_line_option, ','); 00156 for (vector<string>::size_type i=0, n=names_files.size() ; i<n ; ++i) { 00157 vector<string> namefile = split(names_files[i], ':'); 00158 if (namefile.size() != 2) 00159 PLERROR("Cannot understand '%s' for specifying a global calendar.", 00160 names_files[i].c_str()); 00161 string calname = namefile[0]; 00162 string filename = namefile[1]; 00163 VMat dates_vmat = getDataSet(filename); 00164 Vec dates_vec = dates_vmat.getColumn(0); 00165 Calendar::setGlobalCalendar(calname, 00166 Calendar::makeCalendar(dates_vec)); 00167 perr << "Set global calendar \"" << calname << "\" from file \"" << filename << '"' << endl; 00168 } 00169 } 00170 00171 static string global_options( vector<string>& command_line) 00172 { 00173 int argc = int(command_line.size()); 00174 00175 // Note that the findpos function (stringutils.h) returns -1 if the 00176 // option is not found. 00177 int profile_pos = findpos( command_line, "--profile" ); 00178 int profile_wall_pos = findpos( command_line, "--profile-wall" ); 00179 if(profile_pos != -1 || profile_wall_pos != -1) 00180 Profiler::pl_profile_activate(); 00181 // Note that the findpos function (stringutils.h) returns -1 if the 00182 // option is not found. 00183 int no_version_pos = findpos( command_line, "--no-version" ); 00184 00185 // If we don't want no progress bars 00186 int no_progress_bars = findpos( command_line, "--no-progress" ); 00187 00188 int windows_endl = findpos( command_line, "--windows_endl" ); 00189 00190 // Note that the verbosity_value_pos IS NOT EQUAL TO verbosity_pos+1 if 00191 // (verbosity_pos == -1)!!! 00192 int verbosity_pos = findpos( command_line, "--verbosity" ); 00193 int verbosity_value_pos = -1; // ... 00194 int quiet_pos = findpos( command_line, "--quiet" ); 00195 VerbosityLevel verbosity_value = VLEVEL_NORMAL; 00196 00197 if ( verbosity_pos != -1 ) 00198 { 00199 // ... here we can set verbosity_value_pos: 00200 verbosity_value_pos = verbosity_pos+1; 00201 if ( verbosity_value_pos >= argc ) 00202 PLERROR("Option --verbosity must be followed by a VerbosityLevel name " 00203 "or by an integer value."); 00204 verbosity_value = 00205 PL_Log::vlevelFromString( command_line[verbosity_value_pos] ); 00206 } 00207 // set verbosity level now so that it is valid for the rest of global_options 00208 PL_Log::instance().verbosity( verbosity_value ); 00209 00210 /* 00211 int option_level_pos= findpos(command_line, "--option-level"); 00212 int option_level_value_pos= -1; 00213 if (option_level_pos != -1) 00214 { 00215 option_level_value_pos= option_level_pos+1; 00216 if(option_level_value_pos >= argc) 00217 PLERROR("Option --option-level must be followed by an OptionLevel."); 00218 OptionBase::setCurrentOptionLevel(OptionBase::optionLevelFromString(command_line[option_level_value_pos])); 00219 } 00220 */ 00221 00222 // Option to enable logging for the specified modules, specified as 00223 // --enable-logging module1,module2,module3,... i.e. as a comma-separated 00224 // list of modules (without spaces). Special keywords __ALL__ and __NONE__ 00225 // can be specified to log for all modules or no modules respectively. 00226 int enable_logging_pos = findpos(command_line, "--enable-logging"); 00227 int enabled_modules_pos = -1; 00228 if (enable_logging_pos != -1) 00229 { 00230 enabled_modules_pos = enable_logging_pos+1; 00231 if (enabled_modules_pos >= argc) 00232 PLERROR("Option --enable-logging must be followed by a list of the form\n" 00233 "module1,module2,module3,... (comma-separated list without spaces)"); 00234 vector<string> modules = split(command_line[enabled_modules_pos], ','); 00235 PL_Log::instance().enableNamedLogging(modules); 00236 } 00237 00238 // Option to establish global calendars loaded from a matrix 00239 int global_calendar_pos = findpos(command_line, "--global-calendars"); 00240 int global_calendar_value_pos = -1; 00241 if (global_calendar_pos != -1) 00242 { 00243 global_calendar_value_pos = global_calendar_pos+1; 00244 if (global_calendar_value_pos >= argc) 00245 PLERROR("Option --global-calendars must be followed by a list of the form\n" 00246 "CalendarName1:CalendarFilename1,CalendarName2:CalendarFilename2,..."); 00247 set_global_calendars(command_line[global_calendar_value_pos]); 00248 } 00249 00250 // Option for parallel processing through PLearnService 00251 int servers_pos = findpos(command_line, "--servers"); 00252 int serversfile_pos = -1; 00253 if (servers_pos != -1) 00254 { 00255 serversfile_pos = servers_pos+1; 00256 if ( serversfile_pos >= argc) 00257 PLERROR("Option --servers must be followed by the name of a servers file containing a list of hostname pid tcpport\n"); 00258 string serversfile = command_line[serversfile_pos]; 00259 PLearnService::instance().connectToServers(serversfile); 00260 } 00261 00262 // The following removes the options from the command line. It also 00263 // parses the plearn command as being the first non-optional argument on 00264 // the line. IF ANY OPTION IS ADDED, PLEASE MAKE SURE TO REMOVE IT BY 00265 // ADDING A CONDITION IN THE if STATEMENT. 00266 int cleaned = 0; 00267 string the_command = ""; 00268 vector<string> old( command_line ); 00269 00270 for ( int c=0; c < argc; c++ ) 00271 // Neglecting to copy options 00272 if ( c != no_version_pos && 00273 c != profile_pos && 00274 c != profile_wall_pos && 00275 c != no_progress_bars && 00276 c != windows_endl && 00277 c != verbosity_pos && 00278 c != verbosity_value_pos && 00279 c != enable_logging_pos && 00280 c != enabled_modules_pos && 00281 c != global_calendar_pos && 00282 c != global_calendar_value_pos && 00283 c != servers_pos && 00284 c != quiet_pos && 00285 c != serversfile_pos /*&& 00286 c != option_level_pos && 00287 c != option_level_value_pos*/ 00288 ) 00289 { 00290 if ( the_command == "" ) 00291 { 00292 the_command = old[c]; 00293 00294 // If it is not a command, then it is a file that must be forwarded 00295 // to the run command (See the is_command function). 00296 if ( !is_command( the_command ) ) 00297 command_line[cleaned++] = old[c]; 00298 } 00299 else 00300 command_line[cleaned++] = old[c]; 00301 } 00302 command_line.resize( cleaned ); // Truncating the end of the vector. 00303 00304 if (no_version_pos == -1 && quiet_pos == -1){ 00305 output_version( ); 00306 #ifdef _OPENMP 00307 pout<<"Using OPENMP with "+tostring(omp_get_max_threads())+" threads."<<endl; 00308 #endif 00309 } 00310 if (no_progress_bars != -1) 00311 ProgressBar::setPlugin(new NullProgressBarPlugin); 00312 00313 if (windows_endl != -1) 00314 PStream::windows_endl = true; 00315 00316 if (enabled_modules_pos != -1 && quiet_pos == -1) 00317 perr << "Logging enabled for modules: " 00318 << join(PL_Log::instance().namedLogging(), ", ") 00319 << endl; 00320 00321 return the_command; 00322 } 00323 00324 void plearn_terminate_handler() 00325 { 00326 perr << "PLEARN UNUSUAL TERMINATION: plearn_terminate_handler called, probably due \n" 00327 << "to second exception thrown while unwinding stack following a first \n" 00328 << "exception. ABORTING!" << endl; 00329 abort(); 00330 } 00331 00332 int plearn_main( int argc, char** argv, 00333 int major_version, int minor_version, int fixlevel ) 00334 { 00335 setVersion(major_version, minor_version, fixlevel); 00336 00337 // Establish the terminate handler that's called in situations of 00338 // double-fault. 00339 set_terminate(plearn_terminate_handler); 00340 00341 //catch interrup signal and throw an PLERROR 00342 catch_interrupt_signal(); 00343 00344 vector<string> command_line; 00345 vector<string> command_line_orig; 00346 00347 int EXIT_CODE = 0; 00348 try { 00349 00350 #if USING_MPI 00351 PLMPI::init(&argc, &argv); 00352 #endif 00353 00354 seed(); 00355 00356 // set program name 00357 prgname(argv[0]); 00358 00359 command_line = stringvector(argc-1, argv+1); 00360 command_line_orig = command_line; 00361 string command = global_options(command_line); 00362 00363 if ( command == "" ) 00364 { 00365 perr << "Type '" << prgname() << " help' for help" << endl; 00366 return 0; 00367 } 00368 00369 Profiler::pl_profile_start("Prog"); 00370 00371 PLearnCommandRegistry::run(command, command_line); 00372 #if USING_MPI 00373 PLMPI::finalize(); 00374 #endif 00375 00376 } // end of try 00377 catch(const PLearnError& e) 00378 { 00379 perr << "FATAL ERROR: " << e.message() << endl; 00380 EXIT_CODE = 1; 00381 } 00382 catch (std::exception& e) 00383 { 00384 perr << "FATAL ERROR thrown by STL : " << e.what() << endl; 00385 EXIT_CODE = 2; 00386 } 00387 catch (...) 00388 { 00389 perr << "FATAL ERROR: uncaught unknown exception " 00390 << "(ex: out-of-memory when allocating a matrix)" << endl; 00391 EXIT_CODE = 2; 00392 } 00393 00394 if(findpos( command_line_orig, "--profile" )!=-1){ 00395 Profiler::pl_profile_end("Prog"); 00396 Profiler::pl_profile_deactivate(); 00397 Profiler::pl_profile_report(perr); 00398 Profiler::pl_profile_reportwall(perr); 00399 }else if(findpos( command_line_orig, "--profile-wall" )!=-1){ 00400 Profiler::pl_profile_end("Prog"); 00401 Profiler::pl_profile_deactivate(); 00402 Profiler::pl_profile_reportwall(perr); 00403 } 00404 return EXIT_CODE; 00405 } 00406 00407 } // end of namespace PLearn 00408 00409 00410 /* 00411 Local Variables: 00412 mode:c++ 00413 c-basic-offset:4 00414 c-file-style:"stroustrup" 00415 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00416 indent-tabs-mode:nil 00417 fill-column:79 00418 End: 00419 */ 00420 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :