Home | History | Annotate | Download | only in pp
      1 /**
      2  * @file common_option.cpp
      3  * Contains common options and implementation of entry point of pp tools
      4  * and some miscelleaneous functions
      5  *
      6  * @remark Copyright 2003 OProfile authors
      7  * @remark Read the file COPYING
      8  *
      9  * @author Philippe Elie
     10  */
     11 
     12 #include <cstdlib>
     13 
     14 #include <iostream>
     15 #include <sstream>
     16 #include <iterator>
     17 #include <cstdlib>
     18 
     19 #include "op_config.h"
     20 #include "locate_images.h"
     21 #include "op_exception.h"
     22 #include "popt_options.h"
     23 #include "cverb.h"
     24 #include "common_option.h"
     25 #include "file_manip.h"
     26 
     27 using namespace std;
     28 
     29 namespace options {
     30 	double threshold = 0.0;
     31 	string threshold_opt;
     32 	string session_dir = OP_SESSION_DIR_DEFAULT;
     33 	string command_options;
     34 	vector<string> image_path;
     35 	string root_path;
     36 }
     37 
     38 namespace {
     39 
     40 vector<string> verbose_strings;
     41 
     42 popt::option common_options_array[] = {
     43 	popt::option(verbose_strings, "verbose", 'V',
     44 		     // FIXME help string for verbose level
     45 		     "verbose output", "all,debug,bfd,level1,sfile,stats,xml"),
     46 	popt::option(options::session_dir, "session-dir", '\0',
     47 		     "specify session path to hold samples database and session data (" OP_SESSION_DIR_DEFAULT ")", "path"),
     48 	popt::option(options::image_path, "image-path", 'p',
     49 		     "comma-separated path to search missing binaries", "path"),
     50 	popt::option(options::root_path, "root", 'R',
     51 		     "path to filesystem to search for missing binaries", "path"),
     52 };
     53 
     54 
     55 double handle_threshold(string threshold)
     56 {
     57 	double value = 0.0;
     58 
     59 	if (threshold.length()) {
     60 		istringstream ss(threshold);
     61 		if (!(ss >> value)) {
     62 			cerr << "illegal threshold value: " << threshold
     63 			     << " allowed range: [0-100]" << endl;
     64 			exit(EXIT_FAILURE);
     65 		}
     66 
     67 		if (value < 0.0 || value > 100.0) {
     68 			cerr << "illegal threshold value: " << threshold
     69 			     << " allowed range: [0-100]" << endl;
     70 			exit(EXIT_FAILURE);
     71 		}
     72 	}
     73 
     74 	cverb << vdebug << "threshold: " << value << endl;;
     75 
     76 	return value;
     77 }
     78 
     79 
     80 vector<string> pre_parse_spec(vector<string> const & non_options)
     81 {
     82 	vector<string> result;
     83 
     84 	for (size_t i = 0; i < non_options.size(); ++i) {
     85 		if (non_options[i] == "{}") {
     86 			result.push_back("{");
     87 			result.push_back("}");
     88 		} else {
     89 			result.push_back(non_options[i]);
     90 		}
     91 	}
     92 
     93 	return result;
     94 }
     95 
     96 
     97 options::spec const parse_spec(vector<string> non_options)
     98 {
     99 	bool in_first = false;
    100 	bool in_second = false;
    101 	bool first = false;
    102 	bool second = false;
    103 	options::spec pspec;
    104 
    105 	non_options = pre_parse_spec(non_options);
    106 
    107 	vector<string>::const_iterator it = non_options.begin();
    108 	vector<string>::const_iterator end = non_options.end();
    109 
    110 	for (; it != end; ++it) {
    111 		if (*it == "{") {
    112 			if (in_first || in_second || second)
    113 				goto fail;
    114 			if (first) {
    115 				in_second = true;
    116 				second = true;
    117 			} else {
    118 				in_first = true;
    119 				first = true;
    120 			}
    121 			continue;
    122 		}
    123 
    124 		if (*it == "}") {
    125 			if (in_first) {
    126 				in_first = false;
    127 			} else if (in_second) {
    128 				in_second = false;
    129 			} else {
    130 				goto fail;
    131 			}
    132 			continue;
    133 		}
    134 
    135 		if (in_first) {
    136 			pspec.first.push_back(*it);
    137 		} else if (in_second) {
    138 			pspec.second.push_back(*it);
    139 		} else {
    140 			pspec.common.push_back(*it);
    141 		}
    142 	}
    143 
    144 	if (in_first || in_second || (first && !second))
    145 		goto fail;
    146 
    147 	if (pspec.first.empty() && pspec.second.size())
    148 		goto fail;
    149 
    150 	if (first && second) {
    151 		pspec.first.insert(pspec.first.begin(), pspec.common.begin(),
    152 		                   pspec.common.end());
    153 		pspec.second.insert(pspec.second.begin(), pspec.common.begin(),
    154 		                   pspec.common.end());
    155 	}
    156 
    157 	return pspec;
    158 fail:
    159 	cerr << "invalid profile specification ";
    160 	copy(non_options.begin(), non_options.end(),
    161 	     ostream_iterator<string>(cerr, " "));
    162 	cerr << endl;
    163 	exit(EXIT_FAILURE);
    164 }
    165 
    166 
    167 options::spec get_options(int argc, char const * argv[])
    168 {
    169 	vector<string> non_options;
    170 	popt::parse_options(argc, argv, non_options);
    171 
    172 	// initialize paths in op_config.h
    173 	init_op_config_dirs(options::session_dir.c_str());
    174 
    175 	if (!options::threshold_opt.empty())
    176 		options::threshold = handle_threshold(options::threshold_opt);
    177 
    178 	if (!verbose::setup(verbose_strings)) {
    179 		cerr << "unknown --verbose= options\n";
    180 		exit(EXIT_FAILURE);
    181 	}
    182 
    183 	// XML generator needs command line options for its header
    184 	ostringstream str;
    185 	for (int i = 1; i < argc; ++i)
    186 		str << argv[i] << " ";
    187 	options::command_options = str.str();
    188 
    189 	return parse_spec(non_options);
    190 }
    191 
    192 }  // anon namespace
    193 
    194 
    195 int run_pp_tool(int argc, char const * argv[], pp_fct_run_t fct)
    196 {
    197 	try {
    198 		return fct(get_options(argc, argv));
    199 	}
    200 	catch (op_runtime_error const & e) {
    201 		cerr << argv[0] << " error: " << e.what() << endl;
    202 	}
    203 	catch (op_fatal_error const & e) {
    204 		cerr << argv[0] << " error: " << e.what() << endl;
    205 	}
    206 	catch (op_exception const & e) {
    207 		cerr << argv[0] << " error: " << e.what() << endl;
    208 	}
    209 	catch (invalid_argument const & e) {
    210 		cerr << argv[0] << " error: " << e.what() << endl;
    211 	}
    212 	catch (exception const & e) {
    213 		cerr << argv[0] << " error: " << e.what() << endl;
    214 	}
    215 	catch (...) {
    216 		cerr << argv[0] << " unknown exception" << endl;
    217 	}
    218 
    219 	return EXIT_FAILURE;
    220 }
    221 
    222 
    223 demangle_type handle_demangle_option(string const & option)
    224 {
    225 	if (option == "none")
    226 		return dmt_none;
    227 	if (option == "smart")
    228 		return dmt_smart;
    229 	if (option == "normal")
    230 		return dmt_normal;
    231 
    232 	throw op_runtime_error("invalid option --demangle=" + option);
    233 }
    234 
    235 
    236 merge_option handle_merge_option(vector<string> const & mergespec,
    237     bool allow_lib, bool exclude_dependent)
    238 {
    239 	using namespace options;
    240 	merge_option merge_by;
    241 
    242 	merge_by.cpu = false;
    243 	merge_by.lib = false;
    244 	merge_by.tid = false;
    245 	merge_by.tgid = false;
    246 	merge_by.unitmask = false;
    247 
    248 	if (!allow_lib)
    249 		merge_by.lib = true;
    250 
    251 	bool is_all = false;
    252 
    253 	vector<string>::const_iterator cit = mergespec.begin();
    254 	vector<string>::const_iterator end = mergespec.end();
    255 
    256 	for (; cit != end; ++cit) {
    257 		if (*cit == "cpu") {
    258 			merge_by.cpu = true;
    259 		} else if (*cit == "tid") {
    260 			merge_by.tid = true;
    261 		} else if (*cit == "tgid") {
    262 			// PP:5.21 tgid merge imply tid merging.
    263 			merge_by.tgid = true;
    264 			merge_by.tid = true;
    265 		} else if ((*cit == "lib" || *cit == "library") && allow_lib) {
    266 			merge_by.lib = true;
    267 		} else if (*cit == "unitmask") {
    268 			merge_by.unitmask = true;
    269 		} else if (*cit == "all") {
    270 			merge_by.cpu = true;
    271 			merge_by.lib = true;
    272 			merge_by.tid = true;
    273 			merge_by.tgid = true;
    274 			merge_by.unitmask = true;
    275 			is_all = true;
    276 		} else {
    277 			cerr << "unknown merge option: " << *cit << endl;
    278 			exit(EXIT_FAILURE);
    279 		}
    280 	}
    281 
    282 	// if --merge all, don't warn about lib merging,
    283 	// it's not user friendly. Behaviour should still
    284 	// be correct.
    285 	if (exclude_dependent && merge_by.lib && allow_lib && !is_all) {
    286 		cerr << "--merge=lib is meaningless "
    287 		     << "with --exclude-dependent" << endl;
    288 		exit(EXIT_FAILURE);
    289 	}
    290 
    291 	return merge_by;
    292 }
    293