#ifdef __OpenBSD__ #include "profil.h" #include "commandbuf.h" #include "debug.h" #include "exceptionstream.h" #include #include #include #include #if defined( __GNUC__) && ( __GNUC__==3) #include namespace { std::string demangle( const std::string& s) { size_t length; int status; char* ss=abi::__cxa_demangle( s.c_str(), 0, &length, &status); if ( status==0) return ss; if ( status==-1) throw std::bad_alloc(); if ( status==-2) return s; if ( status==-3) throw std::runtime_error( "__cxa_demangle returned -3"); abort(); } } #else namespace { std::string demangle( const std::string& s) { return s; } } #endif namespace { struct symbol_t { symbol_t( const std::string& name0, int count0) : name( name0), count( count0) {} std::string name; int count; }; bool compare_count( const symbol_t& a, const symbol_t& b) { return a.count < b.count; } } namespace op59_net { scoped_profil::scoped_profil( size_t buffer_size0, u_long offset0, u_int scale0) : offset( offset0), scale( scale0), buffer( buffer_size0), running( true) { if ( int e = profil( &this->buffer[0], this->buffer.size(), this->offset, this->scale)) { throw exception_stream() << "profil failed, e=" << e << ", buffer_size=" << buffer_size0 << ", offset=" << offset0 << ", scale=" << scale << "\n"; } debug0 << "scoped_profil: buffer_size=" << this->buffer.size() << " (num bins=" << this->buffer.size()/2 << ")" << ", offset=" << this->offset << ", scale=" << this->scale << "\n"; debug0 << "scoped_profil::scoped_profil, clock()=" << clock() << "\n"; } void scoped_profil::stop() { if ( this->running) { debug0 << "scoped_profil::stop, clock()=" << clock() << "\n"; if ( profil( &this->buffer[0], this->buffer.size(), 0, 0)) { throw exception_stream() << "scoped_profil::stop(): profil failed"; } this->running = false; //std::vector< char>().swap( this->buffer); //this->scale = 0; } } struct tempfilename { tempfilename() : filename( tmpnam( NULL)) {} ~tempfilename() { remove( this->filename.c_str()); } std::string filename; }; void scoped_profil::output( const std::string& exe, const std::string& outfile) { this->stop(); uint16_t* data = (uint16_t*) &this->buffer[0]; tempfilename nm_outname; jules::ccmde() << "nm -Cne " << exe << " >" << nm_outname.filename << std::flush; /* need the -C option even though we also use g++'s demangle function - i think obsd prepends `_' to all symbols? */ std::ifstream in( nm_outname.filename.c_str()); std::ofstream out( outfile.c_str()); out << "Profile stats for executable `" << this->exe << "\n"; out << "profil stats: buffer size=" << this->buffer.size() << ", offset=" << this->offset << ", scale=" << this->scale << "\n" << "num bins=" << this->buffer.size()/2 << ", bin size=" << 1.0*2*65536/this->scale << ".\n\n"; std::vector< symbol_t> symbols; std::string symbol = "address 0"; unsigned int address= 0; int total_counts = 0; for(;;) { unsigned int address2; in >> std::hex >> address2; char a = in.get(); char b = in.get(); char c = in.get(); char d = in.get(); char e = in.get(); (void) a; (void) b; (void) c; (void) d; (void) e; std::string symbol2; std::getline( in, symbol2); symbol2 = demangle( symbol2); if ( !in) break; debug0 << "0x" << std::hex << address << ": " << symbol2 << "\n"; /* deal with [address,address2>. we round the bin number up if it starts just before address. */ int bin_begin = (65535+(address -this->offset)/2*this->scale)/65536; int bin_end = (65535+(address2-this->offset)/2*this->scale)/65536; out << "0x" << std::hex << address << std::dec << "=" << address << ": " << symbol << ":\n"; int total_count_for_this_symbol = 0; for ( int bin=bin_begin; bin= (int) this->buffer.size()) { out << " no data gathered\n"; break; } total_count_for_this_symbol += data[ bin]; unsigned int bin_address=this->offset + 2*65536*bin/this->scale; out << " + " << std::setw( 8) << (bin_address-address) << ": " << data[ bin] << "\n"; } symbols.push_back( symbol_t( symbol, total_count_for_this_symbol)); total_counts += total_count_for_this_symbol; address = address2; symbol = symbol2; } out << "\n" << "total counts = " << total_counts << "\n" << "Sorted by counts:\n"; std::sort( symbols.begin(), symbols.end(), compare_count); int cumlative_total=0; for ( int i=symbols.size()-1; i>=0; --i) { cumlative_total += symbols[i].count; out << std::setw( 5) << symbols[i].count << " (" << std::setw( 5) << std::setprecision( 2) //<< std::ios::fixed << ( 100.0 * symbols[i].count / total_counts) << "%, " << ( 100.0*cumlative_total/total_counts) << "%)" << ": " << symbols[i].name << "\n"; } } scoped_profil::~scoped_profil() { this->stop(); } } #endif