PLearn 0.1
plearn_main.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines