From: Philippe E. <ph...@us...> - 2004-01-20 13:49:35
|
Update of /cvsroot/oprofile/oprofile/libutil++ In directory sc8-pr-cvs1:/tmp/cvs-serv2618/libutil++ Modified Files: cverb.cpp cverb.h op_bfd.cpp Log Message: new verbose (cverb) handling, see cverb.h for the predefined verbose object Index: cverb.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/cverb.cpp,v retrieving revision 1.7 retrieving revision 1.8 diff -u -p -d -r1.7 -r1.8 --- cverb.cpp 1 Jan 2004 19:39:36 -0000 1.7 +++ cverb.cpp 20 Jan 2004 13:49:32 -0000 1.8 @@ -2,7 +2,7 @@ * @file cverb.cpp * verbose output stream * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002, 2004 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie @@ -11,22 +11,119 @@ #include <fstream> #include <iostream> +#include <map> +#include <string> + #include "cverb.h" using namespace std; +cverb_object cverb; +verbose vlevel1("level1"); +verbose vlevel2("level2"); +verbose vdebug("debug"); +verbose vstats("stats"); +verbose vsfile("sfile"); + +namespace { + // The right way is to use: ofstream fout; but cverb(fout.rdbuf()) receive // a null pointer and stl shipped with 2.91 segfault. ofstream fout("/dev/null"); -ostream cverb(fout.rdbuf()); +ostream null_stream(fout.rdbuf()); -void set_verbose(bool verbose) +// Used to setup the bad bit in our null stream so output will fail earlier +// and overhead will be smaller. +struct setup_stream { + setup_stream(); +}; + +setup_stream::setup_stream() { - // Note: should really be std::ios_base::badbit - // but for now the old version will do - - if (verbose) - cverb.rdbuf(cout.rdbuf()); - else - cverb.clear(ios::badbit); + null_stream.clear(ios::badbit); +} + +setup_stream setup; + +// We use a multimap because user can create multiple verbose object with +// the same name, these are synonymous, setting up one to true will setup +// all with the same name to true. +typedef std::multimap<std::string, verbose *> recorder_t; +// The recorder is lazilly created by verbose object ctor +static recorder_t * object_map; + +} // anonymous namespace + + +verbose::verbose(char const * name) + : + set(false) +{ + // all params is treated a part, there is no need to create a + // verbose all("all"); it's meaningless. "all" verbose named object is + // reserved. + if (strcmp(name, "all") == 0) + return; + if (!object_map) + object_map = new recorder_t; + object_map->insert(recorder_t::value_type(name, this)); +} + + +verbose verbose::operator|(verbose const & rhs) +{ + verbose result(*this); + result.set = result.set || rhs.set; + return result; +} + + +verbose verbose::operator&(verbose const & rhs) +{ + verbose result(*this); + result.set = result.set && rhs.set; + return result; +} + + +bool verbose::setup(string const & name) +{ + if (name == "all") { + null_stream.rdbuf(cout.rdbuf()); + null_stream.clear(); + return true; + } + if (!object_map) + object_map = new recorder_t; + pair<recorder_t::iterator, recorder_t::iterator> p_it = + object_map->equal_range(name); + if (p_it.first == p_it.second) + return false; + for (; p_it.first != p_it.second; ++p_it.first) + p_it.first->second->set = true; + return true; +} + + +bool verbose::setup(vector<string> const & names) +{ + for (size_t i = 0; i < names.size(); ++i) + if (!setup(names[i])) + return false; + return true; +} + + +/** + * We don't use the out object, all output are directed to the null stream + * or to cout. This is a real limitation we must be aware. That come from + * the fact I want chained output to work ala: + * cverb << stats << "foo" << debug << "blah"; + * This mean a real misuse of verbose output will be: + * ofstream fout("logfile"); + * fout << debug << "foo"; + */ +ostream& operator<<(cverb_object & /*out*/, verbose const & v) +{ + return v.set ? cout : null_stream; } Index: cverb.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/cverb.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -p -d -r1.3 -r1.4 --- cverb.h 1 Jan 2004 19:39:36 -0000 1.3 +++ cverb.h 20 Jan 2004 13:49:32 -0000 1.4 @@ -2,7 +2,7 @@ * @file cverb.h * verbose output stream * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002, 2004 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie @@ -13,19 +13,71 @@ #define CVERB_H #include <iosfwd> +#include <string> +#include <vector> -/** verbose outpust stream, all output through this stream are made only - * if a set_verbose(true); call is issued. +struct cverb_object { }; + +/** + * verbose object, all output through this stream are made only + * if a verbose object with a true state is injected in the stream. */ -extern std::ostream cverb; +extern cverb_object cverb; -/** - * @param verbose: verbose state - * - * Set the cverb ostream in a verbose/non verbose mode depending on the - * verbose parameter. Currently set_verbose() can be called only one time. If - * this function is never called the default state of cverb is non-verbose mode +/** + * typical use: + * declare some verbose global object: + * verbose debug("debug"); + * verbose stats("stats"); + * verbose level2("level2"); + * + * setup from command line the state of these objects + * + * verbose::setup(command_line_args_to'--verbose='); + * + * cverb << stats << "stats\n"; + * cverb << (stats&level2) << "very verbose stats\n" + * cverb << (stats|debug) << "bar\n"; + * these will give a compile time error + * cverb << stats << "foo" << debug << "bar"; + * cout << stats << "foo"; + * + * In critical code path cverb can be used in the more efficient way: + * if (cerb << vdebug) + * cverb << vdebug << "foo" << "bar"; + * the condition test the fails bit for the returned stream while the later + * build a sentry object for each << (more efficient even with one level of <<) */ -void set_verbose(bool verbose); +class verbose { + friend class verbose_recorder; + friend std::ostream & operator<<(cverb_object &, verbose const &); +public: + /** + * create a verbose object named name, the ctor auto-register name + * as a verbose object, the set state can be intialized through + * verbose::setup(name) + */ + verbose(char const * name); + + verbose operator|(verbose const &); + verbose operator&(verbose const &); + + /// Return false if this named verbose object has not be registred. + static bool setup(std::string const &); + /// convenient interface calling the above for string in args + static bool setup(std::vector<std::string> const & args); +private: + bool set; +}; + +/** + * predefined general purpose verbose object, comment give their names + */ +extern verbose vlevel1; /**< named "level1" */ +extern verbose vlevel2; /**< named "level2" */ +extern verbose vdebug; /**< named "debug" */ +extern verbose vstats; /**< named "stats" */ +// all sample filename manipulation. +extern verbose vsfile; /**< named "vfsfile" */ #endif /* !CVERB_H */ Index: op_bfd.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/op_bfd.cpp,v retrieving revision 1.45 retrieving revision 1.46 diff -u -p -d -r1.45 -r1.46 --- op_bfd.cpp 18 Jan 2004 14:09:21 -0000 1.45 +++ op_bfd.cpp 20 Jan 2004 13:49:32 -0000 1.46 @@ -33,18 +33,20 @@ using namespace std; namespace { +verbose vbfd("bfd"); + bfd * open_bfd(string const & file) { /* bfd keeps its own reference to the filename char *, * so it must have a lifetime longer than the ibfd */ bfd * ibfd = bfd_openr(file.c_str(), NULL); if (!ibfd) { - cverb << "bfd_openr failed for " << file << endl; + cverb << vbfd << "bfd_openr failed for " << file << endl; goto out_fail; } char ** matching; if (!bfd_check_format_matches(ibfd, bfd_object, &matching)) { - cverb << "BFD format failure for " << file << endl; + cverb << vbfd << "BFD format failure for " << file << endl; ibfd = NULL; } @@ -64,14 +66,14 @@ separate_debug_file_exists(string const if (!file) return false; - cverb << "found " << name; + cverb << vbfd << "found " << name; while (file) { file.read(buffer, sizeof(buffer)); file_crc = calc_crc32(file_crc, reinterpret_cast<unsigned char *>(&buffer[0]), file.gcount()); } - cverb << " with crc32 = " << hex << file_crc << endl; + cverb << vbfd << " with crc32 = " << hex << file_crc << endl; return crc == file_crc; } @@ -83,7 +85,7 @@ get_debug_link_info(bfd * ibfd, { asection * sect; - cverb << "fetching .gnu_debuglink section" << endl; + cverb << vbfd << "fetching .gnu_debuglink section" << endl; sect = bfd_get_section_by_name(ibfd, ".gnu_debuglink"); if (sect == NULL) @@ -91,7 +93,8 @@ get_debug_link_info(bfd * ibfd, bfd_size_type debuglink_size = bfd_section_size(ibfd, sect); char contents[debuglink_size]; - cverb << ".gnu_debuglink section has size " << debuglink_size << endl; + cverb << vbfd + << ".gnu_debuglink section has size " << debuglink_size << endl; bfd_get_section_contents(ibfd, sect, reinterpret_cast<unsigned char *>(contents), @@ -105,7 +108,7 @@ get_debug_link_info(bfd * ibfd, crc32 = bfd_get_32(ibfd, reinterpret_cast<bfd_byte *>(contents + crc_offset)); filename = string(contents, filename_len); - cverb << ".gnu_debuglink filename is " << filename << endl; + cverb << vbfd << ".gnu_debuglink filename is " << filename << endl; return true; } @@ -132,7 +135,7 @@ find_separate_debug_file(bfd * ibfd, if (global.size() > 0 && global.at(global.size() - 1) != '/') global += '/'; - cverb << "looking for debugging file " << basename + cverb << vbfd << "looking for debugging file " << basename << " with crc32 = " << hex << crc32 << endl; string first_try(dir + basename); @@ -206,7 +209,7 @@ op_bfd::op_bfd(string const & fname, str ibfd = open_bfd(filename); if (!ibfd) { - cverb << "open_bfd failed for " << filename << endl; + cverb << vbfd << "open_bfd failed for " << filename << endl; ok = false; goto out_fail; } @@ -216,8 +219,9 @@ op_bfd::op_bfd(string const & fname, str asection const * sect = bfd_get_section_by_name(ibfd, ".text"); if (sect) { text_offset = sect->filepos; - io_state state(cverb); - cverb << ".text filepos " << hex << text_offset << endl; + io_state state(cverb << vbfd); + cverb << vbfd + << ".text filepos " << hex << text_offset << endl; } for (sect = ibfd->sections; sect; sect = sect->next) { @@ -233,7 +237,8 @@ op_bfd::op_bfd(string const & fname, str string dirname(filename.substr(0, filename.rfind('/'))); if (find_separate_debug_file (ibfd, dirname, global, debug_filename)) { - cverb << "now loading: " << debug_filename << endl; + cverb << vbfd + << "now loading: " << debug_filename << endl; dbfd = open_bfd(debug_filename); if (dbfd) { for (sect = dbfd->sections; sect; @@ -246,9 +251,8 @@ op_bfd::op_bfd(string const & fname, str } else { // .debug is optional, so will not fail if // problem opening file. - cverb << "unable to open: " << debug_filename - << endl; - // debug_filename = NULL; + cverb << vbfd << "unable to open: " + << debug_filename << endl; } } } @@ -450,15 +454,17 @@ void op_bfd::add_symbols(op_bfd::symbols if (symbols.empty()) symbols.push_back(create_artificial_symbol()); - cverb << "number of symbols before filtering " << symbols.size() << endl; + cverb << vbfd << "number of symbols before filtering " + << symbols.size() << endl; symbols_found_t::iterator it; - it = remove_if(symbols.begin(), symbols.end(), remove_filter(symbol_filter)); + it = remove_if(symbols.begin(), symbols.end(), + remove_filter(symbol_filter)); symbols.erase(it, symbols.end()); copy(symbols.begin(), symbols.end(), back_inserter(syms)); - cverb << "number of symbols now " << syms.size() << endl; + cverb << vbfd << "number of symbols now " << syms.size() << endl; } @@ -631,18 +637,21 @@ void op_bfd::get_symbol_range(symbol_ind { op_bfd_symbol const & sym = syms[sym_idx]; - io_state state(cverb); + io_state state(cverb << (vbfd&vlevel1)); - cverb << "symbol " << sym.name() << ", value " << hex << sym.value() << endl; + cverb << (vbfd&vlevel1) << "symbol " << sym.name() + << ", value " << hex << sym.value() << endl; start = sym.filepos(); if (sym.symbol()) { - cverb << "in section " << sym.symbol()->section->name - << ", filepos " << hex << sym.symbol()->section->filepos << endl; + cverb << (vbfd&vlevel1) << "in section " + << sym.symbol()->section->name << ", filepos " + << hex << sym.symbol()->section->filepos << endl; } end = start + syms[sym_idx].size(); - cverb << "start " << hex << start << ", end " << end << endl; + cverb << (vbfd&vlevel1) + << "start " << hex << start << ", end " << end << endl; if (start >= file_size + text_offset) { ostringstream os; |