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
00018
00019 #if 0
00020 extern "C" {
00021
00022 #define DMGL_AUTO (1 << 8)
00023 extern char* cplus_demangle(const char *mangled, int options);
00024 }
00025 #endif
00026
00027
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
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
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
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
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;
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
00213
00214
00215 last_good_entry.addr_ =
00216 function_address ? function_address : value;
00217
00218 entry = &last_good_entry;
00219 } else {
00220
00221
00222
00223
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
00259
00260 int setsize = symset.size();
00261 int edgesize = 0;
00262 Viter vsyms;
00263 vsyms.reserve(setsize);
00264
00265
00266 VertexSet::const_iterator isym(symset.begin()),esym(symset.end());
00267 while(isym!=esym) {
00268
00269 vsyms.push_back(isym);
00270 ++isym;
00271 }
00272
00273
00274
00275
00276 std::sort(vsyms.begin(), vsyms.end(), idSort);
00277
00278
00279
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
00286 ULVec pathcopy(pat_it_beg->tree_);
00287
00288 std::sort(pathcopy.begin(), pathcopy.end());
00289 ULVec::iterator iter = unique(pathcopy.begin(),pathcopy.end());
00290 ULVec::iterator cop_beg(pathcopy.begin());
00291
00292 while(cop_beg!=iter) {
00293
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
00300
00301
00302 } else {
00303 --sym_iter;
00304
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);
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
00322
00323
00324
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
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
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
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