common_option.cpp

Go to the documentation of this file.
00001 
00012 #include <cstdlib>
00013 
00014 #include <iostream>
00015 #include <sstream>
00016 #include <iterator>
00017 #include <cstdlib>
00018 
00019 #include "op_config.h"
00020 #include "locate_images.h"
00021 #include "op_exception.h"
00022 #include "popt_options.h"
00023 #include "cverb.h"
00024 #include "common_option.h"
00025 #include "file_manip.h"
00026 
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030 #include <limits.h>
00031 
00032 using namespace std;
00033 
00034 namespace options {
00035     double threshold = 0.0;
00036     string threshold_opt;
00037     string session_dir;
00038     string command_options;
00039     vector<string> image_path;
00040     string root_path;
00041 }
00042 
00043 namespace {
00044 
00045 
00046 vector<string> verbose_strings;
00047 
00048 popt::option common_options_array[] = {
00049     popt::option(verbose_strings, "verbose", 'V',
00050              // FIXME help string for verbose level
00051              "verbose output", "all,debug,bfd,level1,sfile,stats,xml"),
00052     popt::option(options::session_dir, "session-dir", '\0',
00053              "specify session path to hold samples database and session data (" OP_SESSION_DIR_DEFAULT ")", "path"),
00054     popt::option(options::image_path, "image-path", 'p',
00055              "comma-separated path to search missing binaries", "path"),
00056     popt::option(options::root_path, "root", 'R',
00057              "path to filesystem to search for missing binaries", "path"),
00058 };
00059 
00060 int session_dir_supplied;
00061 
00062 double handle_threshold(string threshold)
00063 {
00064     double value = 0.0;
00065 
00066     if (threshold.length()) {
00067         istringstream ss(threshold);
00068         if (!(ss >> value)) {
00069             cerr << "illegal threshold value: " << threshold
00070                  << " allowed range: [0-100]" << endl;
00071             exit(EXIT_FAILURE);
00072         }
00073 
00074         if (value < 0.0 || value > 100.0) {
00075             cerr << "illegal threshold value: " << threshold
00076                  << " allowed range: [0-100]" << endl;
00077             exit(EXIT_FAILURE);
00078         }
00079     }
00080 
00081     cverb << vdebug << "threshold: " << value << endl;;
00082 
00083     return value;
00084 }
00085 
00086 
00087 vector<string> pre_parse_spec(vector<string> const & non_options)
00088 {
00089     vector<string> result;
00090 
00091     for (size_t i = 0; i < non_options.size(); ++i) {
00092         if (non_options[i] == "{}") {
00093             result.push_back("{");
00094             result.push_back("}");
00095         } else {
00096             result.push_back(non_options[i]);
00097         }
00098     }
00099 
00100     return result;
00101 }
00102 
00103 
00104 options::spec const parse_spec(vector<string> non_options)
00105 {
00106     bool in_first = false;
00107     bool in_second = false;
00108     bool first = false;
00109     bool second = false;
00110     options::spec pspec;
00111 
00112     non_options = pre_parse_spec(non_options);
00113 
00114     vector<string>::const_iterator it = non_options.begin();
00115     vector<string>::const_iterator end = non_options.end();
00116 
00117     for (; it != end; ++it) {
00118         if (*it == "{") {
00119             if (in_first || in_second || second)
00120                 goto fail;
00121             if (first) {
00122                 in_second = true;
00123                 second = true;
00124             } else {
00125                 in_first = true;
00126                 first = true;
00127             }
00128             continue;
00129         } 
00130 
00131         if (*it == "}") {
00132             if (in_first) {
00133                 in_first = false;
00134             } else if (in_second) {
00135                 in_second = false;
00136             } else {
00137                 goto fail;
00138             }
00139             continue;
00140         }
00141 
00142         if (in_first) {
00143             pspec.first.push_back(*it);
00144         } else if (in_second) {
00145             pspec.second.push_back(*it);
00146         } else {
00147             pspec.common.push_back(*it);
00148         }
00149     }
00150 
00151     if (in_first || in_second || (first && !second))
00152         goto fail;
00153 
00154     if (pspec.first.empty() && pspec.second.size())
00155         goto fail;
00156 
00157     if (first && second) {
00158         pspec.first.insert(pspec.first.begin(), pspec.common.begin(),
00159                            pspec.common.end());
00160         pspec.second.insert(pspec.second.begin(), pspec.common.begin(),
00161                            pspec.common.end());
00162     }
00163 
00164     return pspec;
00165 fail:
00166     cerr << "invalid profile specification ";
00167     copy(non_options.begin(), non_options.end(),
00168          ostream_iterator<string>(cerr, " "));
00169     cerr << endl;
00170     exit(EXIT_FAILURE);
00171 }
00172 
00173 options::spec get_options(int argc, char const * argv[])
00174 {
00175     vector<string> non_options;
00176     popt::parse_options(argc, argv, non_options);
00177 
00178     // initialize paths in op_config.h
00179     if (options::session_dir.empty()) {
00180         char * cwd;
00181         struct stat sb;
00182         // If <curr_dir>/oprofile_data exists (used by operf), we'll use that as session-dir
00183         cwd = new char[PATH_MAX];
00184         options::session_dir = (getcwd(cwd, PATH_MAX) == NULL) ? "" : cwd;
00185         delete [] cwd;
00186         options::session_dir +="/oprofile_data";
00187         if ((stat(options::session_dir.c_str(), &sb) < 0) ||
00188                 ((sb.st_mode & S_IFMT) != S_IFDIR)) {
00189             // Use the standard default session dir instead
00190             options::session_dir = "/var/lib/oprofile";
00191         }
00192         session_dir_supplied = 0;
00193     } else {
00194         session_dir_supplied = 1;
00195     }
00196     init_op_config_dirs(options::session_dir.c_str());
00197 
00198     if (!options::threshold_opt.empty())
00199         options::threshold = handle_threshold(options::threshold_opt);
00200 
00201     if (!verbose::setup(verbose_strings)) {
00202         cerr << "unknown --verbose= options\n";
00203         exit(EXIT_FAILURE);
00204     }
00205 
00206     // XML generator needs command line options for its header
00207     ostringstream str;
00208     for (int i = 1; i < argc; ++i)
00209         str << argv[i] << " ";
00210     options::command_options = str.str();
00211 
00212     return parse_spec(non_options);
00213 }
00214 
00215 }  // anon namespace
00216 
00217 
00218 int run_pp_tool(int argc, char const * argv[], pp_fct_run_t fct)
00219 {
00220     try {
00221         return fct(get_options(argc, argv));
00222     }
00223     catch (op_runtime_error const & e) {
00224         cerr << argv[0] << " error: " << e.what() << endl;
00225     }
00226     catch (op_fatal_error const & e) {
00227         cerr << argv[0] << " error: " << e.what() << endl;
00228     }
00229     catch (op_exception const & e) {
00230         cerr << argv[0] << " error: " << e.what() << endl;
00231     }
00232     catch (invalid_argument const & e) {
00233         cerr << argv[0] << " error: " << e.what() << endl;
00234     }
00235     catch (exception const & e) {
00236         cerr << argv[0] << " error: " << e.what() << endl;
00237     }
00238     catch (...) {
00239         cerr << argv[0] << " unknown exception" << endl;
00240     }
00241 
00242     return EXIT_FAILURE;
00243 }
00244 
00245 
00246 demangle_type handle_demangle_option(string const & option)
00247 {
00248     if (option == "none")
00249         return dmt_none;
00250     if (option == "smart")
00251         return dmt_smart;
00252     if (option == "normal")
00253         return dmt_normal;
00254 
00255     throw op_runtime_error("invalid option --demangle=" + option);
00256 }
00257 
00258 
00259 merge_option handle_merge_option(vector<string> const & mergespec,
00260     bool allow_lib, bool exclude_dependent)
00261 {
00262     using namespace options;
00263     merge_option merge_by;
00264 
00265     merge_by.cpu = false;
00266     merge_by.lib = false;
00267     merge_by.tid = false;
00268     merge_by.tgid = false;
00269     merge_by.unitmask = false;
00270 
00271     if (!allow_lib)
00272         merge_by.lib = true;
00273 
00274     bool is_all = false;
00275 
00276     vector<string>::const_iterator cit = mergespec.begin();
00277     vector<string>::const_iterator end = mergespec.end();
00278 
00279     for (; cit != end; ++cit) {
00280         if (*cit == "cpu") {
00281             merge_by.cpu = true;
00282         } else if (*cit == "tid") {
00283             merge_by.tid = true;
00284         } else if (*cit == "tgid") {
00285             // PP:5.21 tgid merge imply tid merging.
00286             merge_by.tgid = true;
00287             merge_by.tid = true;
00288         } else if ((*cit == "lib" || *cit == "library") && allow_lib) {
00289             merge_by.lib = true;
00290         } else if (*cit == "unitmask") {
00291             merge_by.unitmask = true;
00292         } else if (*cit == "all") {
00293             merge_by.cpu = true;
00294             merge_by.lib = true;
00295             merge_by.tid = true;
00296             merge_by.tgid = true;
00297             merge_by.unitmask = true;
00298             is_all = true;
00299         } else {
00300             cerr << "unknown merge option: " << *cit << endl;
00301             exit(EXIT_FAILURE);
00302         }
00303     }
00304 
00305     // if --merge all, don't warn about lib merging,
00306     // it's not user friendly. Behaviour should still
00307     // be correct.
00308     if (exclude_dependent && merge_by.lib && allow_lib && !is_all) {
00309         cerr << "--merge=lib is meaningless "
00310              << "with --exclude-dependent" << endl;
00311         exit(EXIT_FAILURE);
00312     }
00313 
00314     return merge_by;
00315 }
00316 
00317 bool was_session_dir_supplied(void)
00318 {
00319     return session_dir_supplied;
00320 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1