CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FWCore/Services/src/ProfParse.cc

Go to the documentation of this file.
00001 
00002 #include <algorithm>
00003 #include <fstream>
00004 #include <iostream>
00005 #include <map>
00006 #include <set>
00007 #include <sstream>
00008 #include <stdexcept>
00009 #include <string>
00010 #include <vector>
00011 
00012 #include <dlfcn.h>
00013 #include <unistd.h>
00014 
00015 #include "VertexTracker.h"
00016 
00017 //#include "FWCore/Utilities/interface/Algorithms.h"
00018 
00019 #if 0
00020 extern "C" {
00021   // options:
00022 #define DMGL_AUTO    (1 << 8)
00023   extern char* cplus_demangle(const char *mangled, int options);
00024 }
00025 #endif
00026 
00027 // ----------------- Path tracker class ---------------------
00028 
00029 struct PathTracker
00030 {
00031   PathTracker(): id_(),total_() { }
00032 
00033   mutable unsigned int id_;
00034   mutable unsigned int total_;
00035   ULVec tree_;
00036 
00037   bool operator<(const PathTracker& a) const;
00038   void setID() const { id_=next_id_++; }
00039   void incTotal() const { ++total_; }
00040 
00041   static unsigned int next_id_;
00042 };
00043 
00044 unsigned int PathTracker::next_id_ = 0;
00045 
00046 bool PathTracker::operator<(const PathTracker& a) const
00047 {
00048   return tree_ < a.tree_;
00049 }
00050 
00051 std::ostream& operator<<(std::ostream& ost, const PathTracker& a)
00052 {
00053   ost << a.id_ << " " << a.total_ << " ";
00054   ULVec::const_iterator i(a.tree_.begin()),e(a.tree_.end());
00055   while(i!=e) { ost << (unsigned int)*i << " "; ++i; }
00056   return ost;
00057 }
00058 
00059 // ------------------- utilities --------------------------
00060 
00061 void verifyFile(std::ostream& ost, const std::string& name)
00062 {
00063   if(!ost) {
00064       std::cerr << "cannot open output file " << name << std::endl;
00065       throw std::runtime_error("failed to open output file");
00066   }
00067 }
00068 
00069 
00070 // ------------- more utilities ----------------
00071 
00072 static bool symSort(const VertexSet::const_iterator& a,
00073                     const VertexSet::const_iterator& b)
00074 {
00075   return a->total_as_leaf_ < b->total_as_leaf_;
00076 }
00077 
00078 static bool idSort(const VertexSet::const_iterator& a,
00079                     const VertexSet::const_iterator& b)
00080 {
00081   return a->id_ < b->id_;
00082 }
00083 
00084 static bool idComp(unsigned int id,
00085                     const VertexSet::const_iterator& b)
00086 {
00087   return id < b->id_;
00088 }
00089 
00090 static bool pathSort(const PathSet::const_iterator& a,
00091                     const PathSet::const_iterator& b)
00092 {
00093   return a->total_ < b->total_;
00094 }
00095 
00096 // ------------------ main routine --------------------
00097 
00098 class Reader
00099 {
00100  public:
00101   explicit Reader(int fd):fd_(fd) { }
00102   bool nextSample(VoidVec& vv);
00103  private:
00104   int fd_;
00105 };
00106 
00107 bool Reader::nextSample(VoidVec& vv)
00108 {
00109   unsigned int cnt;
00110   int sz = read(fd_,&cnt,sizeof(unsigned int));
00111 
00112   if(sz<0) {
00113       perror("Reader::nextSample: read count");
00114       std::cerr << "could not read next sample from profile data\n";
00115       return false;
00116   }
00117   if(sz == 0) return false;
00118   if((unsigned)sz<sizeof(unsigned int)) {
00119       std::cerr << "Reader::nextSample: "
00120            << "could not read the correct amount of profile data\n";
00121       return false;
00122   }
00123   if(cnt > 1000) {
00124       std::cerr << "Reader::nextSample: stack length is nonsense " << cnt << "\n";
00125       return false;
00126   }
00127   
00128   vv.resize(cnt);
00129   void** pos = &vv[0];
00130   int byte_cnt = cnt*sizeof(void*);
00131 
00132   while((sz = read(fd_,pos,byte_cnt)) < byte_cnt) {
00133       if(sz < 0) {
00134           perror("Reader::nextSample: read stack");
00135           std::cerr << "could not read stack\n";
00136           return false;
00137       }
00138       byte_cnt -= sz;
00139       pos += sz;
00140   }
00141   return true;
00142 }
00143 
00144 std::string make_name(Dl_info const& info, void* where,
00145                       std::string const& prefix)
00146 {
00147   std::string object_name;
00148   if (info.dli_fname == 0 || info.dli_fname[0] == 0x0) {
00149       std::ostringstream oss;
00150       oss << "no_object_" << where;
00151       return oss.str();
00152   }
00153   if (info.dli_saddr) return info.dli_sname;
00154   std::ostringstream oss;
00155   oss << prefix << where;
00156   return oss.str();
00157 }
00158 
00159 void writeProfileData(int fd, const std::string& prefix)
00160 {
00161   std::string output_tree(prefix+"_paths");
00162   std::string output_names(prefix+"_names");
00163   std::string output_totals(prefix+"_totals");
00164 
00165   std::ofstream nost(output_names.c_str());
00166   std::ofstream tost(output_tree.c_str());
00167   std::ofstream sost(output_totals.c_str());
00168 
00169   verifyFile(nost,output_names);
00170   verifyFile(tost,output_tree);
00171   verifyFile(sost,output_totals);
00172 
00173   VertexSet symset;
00174   PathSet pathset;
00175   std::pair<VertexSet::iterator,bool> irc,prev_irc;
00176   std::pair<PathSet::iterator,bool> prc;
00177 
00178   VoidVec v;
00179   int len=0;
00180   int total=0;
00181   int total_failed=0;
00182   int total_missing=0;
00183   //  int failure_count=0;
00184   Sym last_none_entry;
00185   Sym last_good_entry;
00186   Reader r(fd);
00187   std::string unk("unknown_name");
00188 
00189   while (r.nextSample(v)) {
00190       PathTracker ptrack;
00191       ++total;
00192       len = v.size();
00193       if(len==0) continue; // should never happen!
00194       VoidVec::reverse_iterator c(v.rbegin()),e(v.rend());
00195       bool first_pass=true;
00196 
00197       while(c != e) {
00198           Sym::address_type value = reinterpret_cast<Sym::address_type>(*c);
00199 
00200           const Sym* entry = 0;
00201           Dl_info info;
00202           void* addr = static_cast<void*>(value);
00203 
00204           if(dladdr(addr,&info) != 0) {
00205               std::string name = make_name(info, addr, "unknown_");
00206 
00207               last_good_entry.name_    = name;
00208               last_good_entry.library_ = info.dli_fname;
00209               last_good_entry.id_      = 0;
00210               void* function_address = info.dli_saddr;
00211 
00212               // If we find the address of this function, we make  a
00213               // unique VertexTracker for that function. If not,  we
00214               // make a unique VertexTracker for this exact address.
00215               last_good_entry.addr_  =   
00216                 function_address ? function_address : value;
00217 
00218               entry = &last_good_entry;
00219           } else { // dladdr has failed
00220               /*
00221                 std::cerr << "sample " << total
00222                    << ": dladdr failed for address: " << *c
00223                    << std::endl;
00224               */
00225               ++total_failed;
00226               std::ostringstream oss;
00227               oss << "lookup_failure_" << addr;
00228               last_none_entry.name_    = oss.str();
00229               last_none_entry.library_ = "unknown";
00230               last_none_entry.id_      = Sym::next_id_++;
00231               last_none_entry.addr_    = value;
00232 
00233               entry = &last_none_entry;
00234           }
00235 
00236           irc = symset.insert(VertexTracker(*entry));
00237           if(irc.second) {
00238               irc.first->setID();
00239           }
00240           irc.first->incTotal();
00241           ptrack.tree_.push_back(irc.first->id_);
00242 
00243           if(!first_pass) ++prev_irc.first->edges_[irc.first->id_];
00244           else first_pass=false;
00245 
00246           prev_irc = irc;
00247           ++c;
00248       }
00249 
00250       irc.first->incLeaf();
00251       prc = pathset.insert(ptrack);
00252       if(prc.second) {
00253           prc.first->setID();
00254       }
00255       prc.first->incTotal();
00256   }  
00257 
00258   // ------------------ copy the vertices for sorting and searching ------
00259 
00260   int setsize = symset.size();
00261   int edgesize = 0;
00262   Viter vsyms;
00263   vsyms.reserve(setsize);
00264 
00265   //cout << "------ symset -----" << std::endl;
00266   VertexSet::const_iterator isym(symset.begin()),esym(symset.end());
00267   while(isym!=esym) {
00268       //cout << "     " << *isym << std::endl;
00269       vsyms.push_back(isym);
00270       ++isym;
00271   }
00272 
00273   // ------ calculate samples for parents and percentages in vertices ------
00274 
00275   //edm::sort_all(vsyms,idSort);
00276   std::sort(vsyms.begin(), vsyms.end(), idSort);
00277   //Viter::iterator Vib(vsyms.begin()),Vie(vsyms.end());
00278   //std::cout << "sorted table --------------" << std::endl;
00279   //while(Vib!=Vie) { std::cout << "    " << *(*Vib) << std::endl; ++Vib; }
00280 
00281   PathSet::const_iterator pat_it_beg(pathset.begin()),
00282     pat_it_end(pathset.end());
00283 
00284   while(pat_it_beg!=pat_it_end) {
00285       // get set of unique IDs from the path
00286       ULVec pathcopy(pat_it_beg->tree_);
00287       //edm::sort_all(pathcopy);
00288       std::sort(pathcopy.begin(), pathcopy.end());
00289       ULVec::iterator iter = unique(pathcopy.begin(),pathcopy.end());
00290       ULVec::iterator cop_beg(pathcopy.begin());
00291       //cout << "length of unique = " << distance(cop_beg,iter) << std::endl;
00292       while(cop_beg!=iter) {
00293           //cout << "  entry " << *cop_beg << std::endl;
00294           Viter::iterator sym_iter = upper_bound(vsyms.begin(),vsyms.end(),
00295                                                  *cop_beg,idComp);
00296           if(sym_iter==vsyms.begin()) {
00297               ++total_missing;
00298               /*
00299               std::cerr << "found a missing sym entry for address " << *cop_beg
00300                    << std::endl;
00301               */
00302           } else {
00303               --sym_iter;
00304               //cout << " symiter " << *(*sym_iter) << std::endl;
00305               (*sym_iter)->incPath(pat_it_beg->total_);
00306           }
00307           ++cop_beg;
00308       }
00309 
00310       ++pat_it_beg;
00311   }
00312 
00313   VertexSet::iterator ver_iter(symset.begin()),ver_iter_end(symset.end());
00314   float ftotal = (total != 0 ? (float)total : 1.0); // Avoids possible divide by zero.
00315   while(ver_iter != ver_iter_end) {
00316       ver_iter->percent_leaf_ = (float)ver_iter->total_as_leaf_ / ftotal;
00317       ver_iter->percent_path_ = (float)ver_iter->in_path_ / ftotal;
00318       ++ver_iter;
00319   }
00320 
00321   // -------------- write out the vertices ----------------
00322 
00323 
00324   //edm::sort_all(vsyms,symSort);
00325   std::sort(vsyms.begin(), vsyms.end(), symSort);
00326   Viter::reverse_iterator vvi(vsyms.rbegin()),vve(vsyms.rend());
00327   while(vvi != vve) {
00328       nost << *(*vvi) << "\n";
00329       ++vvi;
00330   }
00331 
00332 
00333   // --------------- write out the paths ------------------ 
00334 
00335   int pathsize = pathset.size();
00336   Piter vpaths;
00337   vpaths.reserve(pathsize);
00338 
00339   PathSet::const_iterator ipath(pathset.begin()),epath(pathset.end());
00340   while(ipath != epath) {
00341       vpaths.push_back(ipath);
00342       ++ipath;
00343   }
00344 
00345   //edm::sort_all(vpaths,pathSort);
00346   std::sort(vpaths.begin(),vpaths.end(),pathSort);
00347 
00348   Piter::reverse_iterator ppi(vpaths.rbegin()),ppe(vpaths.rend());
00349   while(ppi != ppe) {
00350       tost << *(*ppi) << "\n";
00351       ++ppi;
00352   }
00353 
00354   // ------------ totals --------------------
00355   sost << "total_samples " << total << "\n"
00356        << "total_functions " << setsize << "\n"
00357        << "total_paths " << pathsize << "\n"
00358        << "total_edges " << edgesize << std::endl
00359        << "total_failed_lookups " << total_failed << std::endl
00360        << "total_missing_sym_entries " << total_missing << std::endl;
00361 
00362 }
00363 
00364 extern "C" {
00365   void writeProfileDataC(int fd, const std::string& prefix)
00366   {
00367     writeProfileData(fd,prefix);
00368   }
00369 }
00370 
00371 
00372