CMS 3D CMS Logo

IgProfTrace.cc

Go to the documentation of this file.
00001 #include "IgTools/IgProf/src/IgProfTrace.h"
00002 #include "IgTools/IgHook/interface/IgHookTrace.h"
00003 #include <memory.h>
00004 #include <stdio.h>
00005 
00006 static IgProfTrace::Counter FREED;
00007 static const unsigned int RESOURCE_HASH = 1024*1024;
00008 static const unsigned int MEM_POOL_SIZE = 8*1024*1024;
00009 static const int          MERGE_RECS    = 128;
00010 
00012 IgProfTrace::IgProfTrace(int opts)
00013   : options_(opts),
00014     restable_(0),
00015     callcache_(0),
00016     resfree_(0),
00017     stack_(0)
00018 {
00019   if (opts & OptShared)
00020     pthread_mutex_init(&mutex_, 0);
00021 
00022   // If we are tracking resources, allocate a separate slab of memory
00023   // the resource hash table.  This has to be big for large memory
00024   // applications, so it's ok to allocate it separately.  Note the
00025   // memory obtained here starts out as zeroed out.
00026   if (opts & OptResources)
00027     restable_ = (Resource **) allocateRaw(RESOURCE_HASH*sizeof(Resource *));
00028   
00029   // Allocate the call cache next.
00030   callcache_ = (StackCache *) allocateSpace(MAX_DEPTH*sizeof(StackCache));
00031 
00032   // Allocate the stack root node.
00033   stack_ = allocate<Stack>();
00034 
00035   // The resource free list starts out empty.
00036   IGPROF_ASSERT(! resfree_);
00037 }
00038 
00039 IgProfTrace::~IgProfTrace(void)
00040 {
00041   if (restable_)
00042     unallocateRaw(restable_, RESOURCE_HASH*sizeof(Resource *));
00043 }
00044 
00045 IgProfTrace::Stack *
00046 IgProfTrace::childStackNode(Stack *parent, void *address)
00047 {
00048   // Search for the child's call address in the child stack frames.
00049   Stack **kid = &parent->children;
00050   while (*kid)
00051   {
00052     Stack *k = *kid;
00053     if (k->address == address)
00054       return k;
00055 
00056     if ((char *) k->address > (char *) address)
00057       break;
00058 
00059     kid = &k->sibling;
00060   }
00061 
00062   // Didn't find it, add a new child in address-sorted order.
00063   Stack *next = *kid;
00064   Stack *k = *kid = allocate<Stack>();
00065   k->address = address;
00066 #if IGPROF_DEBUG
00067   k->parent = parent;
00068 #endif
00069   k->sibling = next;
00070   k->children = 0;
00071   k->counters = 0;
00072 
00073   return k;
00074 }
00075 
00076 inline IgProfTrace::Counter *
00077 IgProfTrace::initCounter(Counter *&link, CounterDef *def, Stack *frame)
00078 {
00079   Counter *ctr = allocate<Counter>();
00080   ctr->ticks = 0;
00081   ctr->value = 0;
00082   ctr->peak = 0;
00083   ctr->def = def;
00084   ctr->frame = frame;
00085   ctr->next = 0;
00086   ctr->resources = 0;
00087   link = ctr;
00088   return ctr;
00089 }
00090 
00091 inline bool
00092 IgProfTrace::findResource(Record &rec,
00093                           Resource **&rlink,
00094                           Resource *&res,
00095                           CounterDef *def)
00096 {
00097   // Locate the resource in the hash table.
00098   rlink = &restable_[hash(rec.resource) & (RESOURCE_HASH-1)];
00099 
00100   while (Resource *r = *rlink)
00101   {
00102     if (r->resource == rec.resource && r->def == def)
00103     {
00104       res = r;
00105       return true;
00106     }
00107     if (r->resource > rec.resource)
00108       return false;
00109     rlink = &r->nexthash;
00110   }
00111 
00112   return false;
00113 }
00114 
00115 inline void
00116 IgProfTrace::releaseResource(Resource **rlink, Resource *res)
00117 {
00118   IGPROF_ASSERT(res);
00119   IGPROF_ASSERT(rlink);
00120   IGPROF_ASSERT(res->counter);
00121   IGPROF_ASSERT(res->counter != &FREED);
00122   IGPROF_ASSERT(res->counter->resources);
00123   IGPROF_ASSERT(*rlink == res);
00124 
00125   // Deduct the resource from the counter.
00126   Counter *ctr = res->counter;
00127   IGPROF_ASSERT(ctr->value >= res->size);
00128   IGPROF_ASSERT(ctr->ticks > 0);
00129   ctr->value -= res->size;
00130   ctr->ticks--;
00131 
00132   // Unchain from hash and counter lists.
00133   *rlink = res->nexthash;
00134 
00135   if (Resource *prev = res->prevlive)
00136   {
00137     IGPROF_ASSERT(prev->nextlive == res);
00138     prev->nextlive = res->nextlive;
00139   }
00140   else
00141   {
00142     IGPROF_ASSERT(ctr->resources == res);
00143     ctr->resources = res->nextlive;
00144   }
00145 
00146   if (Resource *next = res->nextlive)
00147   {
00148     IGPROF_ASSERT(next->prevlive == res);
00149     next->prevlive = res->prevlive;
00150   }
00151 
00152   // Put it on free list.
00153   memset (res, 0, sizeof (*res));
00154   res->nextlive = resfree_;
00155   res->counter = &FREED;
00156   resfree_ = res;
00157 }
00158 
00159 void
00160 IgProfTrace::releaseResource(Record &rec)
00161 {
00162   // Locate the resource in the hash table.
00163   Resource  **rlink;
00164   Resource  *res = 0;
00165   if (! findResource(rec, rlink, res, rec.def))
00166     // Not found, we missed the allocation, ignore this release.
00167     return;
00168   else
00169     // Found, actually release it.
00170     releaseResource(rlink, res);
00171 }
00172 
00173 void
00174 IgProfTrace::acquireResource(Record &rec, Counter *ctr)
00175 {
00176   IGPROF_ASSERT(ctr);
00177 
00178   // Locate the resource in the hash table.
00179   Resource  **rlink;
00180   Resource  *res = 0;
00181   if (findResource(rec, rlink, res, ctr->def))
00182   {
00183     IgProf::debug("New %s resource 0x%lx of %ju bytes was never freed in %p\n",
00184                   ctr->def->name, rec.resource, res->size, this);
00185 #if IGPROF_DEBUG
00186     int depth = 0;
00187     for (Stack *s = ctr->frame; s; s = s->parent)
00188     {
00189       const char  *sym = 0;
00190       const char  *lib = 0;
00191       int         offset = 0;
00192       int         liboffset = 0;
00193 
00194       IgHookTrace::symbol(s->address, sym, lib, offset, liboffset);
00195       IgProf::debug ("  [%u] %10p %s + %d [%s + %d]\n", ++depth, s->address,
00196                      sym ? sym : "?", offset, lib ? lib : "?", liboffset);
00197     }
00198 #endif
00199 
00200     // Release the resource, then proceed as if we hadn't found it.
00201     releaseResource(rlink, res);
00202   }
00203 
00204   // It wasn't found, insert into the lists as per class documentation.
00205   if ((res = resfree_))
00206     resfree_ = res->nextlive;
00207   else
00208     res = allocate<Resource>();
00209   res->resource = rec.resource;
00210   res->size = rec.amount;
00211   res->nexthash = *rlink;
00212   res->prevlive = 0;
00213   res->nextlive = ctr->resources;
00214   res->counter = ctr;
00215   res->def = rec.def;
00216   ctr->resources = *rlink = res;
00217   if (res->nextlive)
00218     res->nextlive->prevlive = res;
00219 }
00220 
00222 void
00223 IgProfTrace::push(void **stack, int depth, Record *recs, int nrecs)
00224 {
00225   if (options_ & OptShared)
00226     pthread_mutex_lock(&mutex_);
00227 
00228   // Make sure we operate on non-negative depth.  This allows callers
00229   // to do strip off call tree layers without checking for sufficient
00230   // depth themselves.
00231   if (depth < 0)
00232     depth = 0;
00233 
00234   // Look up call stack in the cache.
00235   StackCache    *cache = callcache_;
00236   Stack         *frame = stack_;
00237 
00238   for (int i = 0, valid = 1; i < depth && i < MAX_DEPTH; ++i)
00239   {
00240     void *address = stack[depth-i-1];
00241     if (valid && cache[i].address == address)
00242       frame = cache[i].frame;
00243     else
00244     {
00245       // Look up this call stack child, then cache result.
00246       frame = childStackNode(frame, address);
00247       cache [i].address = address;
00248       cache [i].frame = frame;
00249       valid = 0;
00250     }
00251   }
00252 
00253   // OK, we now have our final call stack node.  Update its counters
00254   // and the resource allocations as defined by "recs".
00255   for (int i = 0; i < nrecs; ++i)
00256   {
00257     Counter **ctr = 0;
00258     Counter *c = 0;
00259 
00260     // If it's a release acquisition or normal tick, update counter.
00261     if (recs[i].type & (COUNT | ACQUIRE))
00262     {
00263       // Locate the counter.
00264       ctr = &frame->counters;
00265       while (*ctr && (*ctr)->def != recs[i].def)
00266         ctr = &(*ctr)->next;
00267 
00268       // If not found, add it.
00269       c = *ctr;
00270       if (! c || c->def != recs[i].def)
00271         c = initCounter(*ctr, recs[i].def, frame);
00272 
00273       // Tick the counter.
00274       if (recs[i].def->type == TICK || recs[i].def->type == TICK_PEAK)
00275         c->value += recs[i].amount;
00276       else if (recs[i].def->type == MAX && c->value < recs[i].amount)
00277         c->value = recs[i].amount;
00278 
00279       if (recs[i].def->type == TICK_PEAK && c->value > c->peak)
00280         c->peak = c->value;
00281 
00282       c->ticks += recs[i].ticks;
00283     }
00284 
00285     // Handle resource record for acquisition.
00286     if (recs[i].type & ACQUIRE)
00287       acquireResource(recs[i], c);
00288 
00289     // Handle resource record for release.  Call stack is empty here.
00290     if (recs[i].type & RELEASE)
00291       releaseResource(recs[i]);
00292   }
00293 
00294   if (options_ & OptShared)
00295     pthread_mutex_unlock(&mutex_);
00296 }
00297 
00298 void
00299 IgProfTrace::mergeFrom(IgProfTrace &other)
00300 {
00301   if (options_ & OptShared)
00302     pthread_mutex_lock(&mutex_);
00303   if (other.options_ & OptShared)
00304     pthread_mutex_lock(&other.mutex_);
00305 
00306   // Scan stack tree and insert each call stack, including resources.
00307   Record recs[MERGE_RECS];
00308   void   *callstack[MAX_DEPTH+1];
00309 
00310   callstack[MAX_DEPTH] = stack_->address; // null really
00311   mergeFrom(0, other.stack_, &callstack[MAX_DEPTH], recs);
00312 
00313   if (other.options_ & OptShared)
00314     pthread_mutex_unlock(&other.mutex_);
00315   if (options_ & OptShared)
00316     pthread_mutex_unlock(&mutex_);
00317 }
00318 
00319 void
00320 IgProfTrace::mergeFrom(int depth, Stack *frame, void **callstack, Record *recs)
00321 {
00322   // Process counters at this call stack level.
00323   int rec = 0;
00324   for (Counter *c = frame->counters; c; c = c->next)
00325   {
00326     if (c->ticks && ! c->resources)
00327     {
00328       if (rec == MERGE_RECS)
00329       {
00330         push(callstack, depth, recs, rec);
00331         rec = 0;
00332       }
00333 
00334       recs[rec].type = COUNT;
00335       recs[rec].def = c->def;
00336       recs[rec].amount = c->value;
00337       recs[rec].ticks = c->ticks;
00338       ++rec;
00339     }
00340     else if (c->ticks)
00341     {
00342       for (Resource *r = c->resources; r; r = r->nextlive)
00343       {
00344         if (rec == MERGE_RECS)
00345         {
00346           push(callstack, depth, recs, rec);
00347           rec = 0;
00348         }
00349 
00350         recs[rec].type = COUNT | ACQUIRE;
00351         recs[rec].def = c->def;
00352         recs[rec].amount = r->size;
00353         recs[rec].ticks = 1;
00354         recs[rec].resource = r->resource;
00355         ++rec;
00356       }
00357     }
00358 
00359     // Adjust the peak counter if necessary.
00360     if (c->def->type == TICK_PEAK && c->peak > c->value)
00361     {
00362       if (rec == MERGE_RECS)
00363       {
00364         push(callstack, depth, recs, rec);
00365         rec = 0;
00366       }
00367 
00368       recs[rec].type = COUNT | ACQUIRE | RELEASE;
00369       recs[rec].def = c->def;
00370       recs[rec].amount = c->peak - c->value;
00371       recs[rec].ticks = 1;
00372       recs[rec].resource = ~((Address) 0);
00373       ++rec;
00374     }
00375   }
00376 
00377   if (rec)
00378     push(callstack, depth, recs, rec);
00379 
00380   // Merge the children.
00381   for (frame = frame->children; frame; frame = frame->sibling)
00382   {
00383     IGPROF_ASSERT(depth < MAX_DEPTH);
00384     callstack[-1] = frame->address;
00385     mergeFrom(depth+1, frame, &callstack[-1], recs);
00386   }
00387 }
00388 
00389 #define INDENT(d) for (int i = 0; i < d; ++i) fputc (' ', stderr)
00390 
00391 void
00392 IgProfTrace::debugDumpStack(Stack *s, int depth)
00393 {
00394   INDENT(2*depth);
00395   fprintf(stderr, "STACK %d frame=%p addr=%p next=%p kids=%p\n",
00396           depth, s, s->address, s->sibling, s->children);
00397 
00398   for (Counter *c = s->counters; c; c = c->next)
00399   {
00400     INDENT(2*depth+1);
00401     fprintf(stderr, "COUNTER ctr=%p %s %ju %ju %ju\n",
00402             c, c->def->name, c->ticks, c->value, c->peak);
00403 
00404     for (Resource *r = c->resources; r; r = r->nextlive)
00405     {
00406       INDENT(2*depth+2);
00407       fprintf(stderr, "RESOURCE res=%p (prev=%p next=%p) %ju %ju\n",
00408               r, r->prevlive, r->nextlive, r->resource, r->size);
00409     }
00410   }
00411 
00412   for (Stack *kid = s->children; kid; kid = kid->sibling)
00413     debugDumpStack(kid, depth+1);
00414 }
00415 
00416 void
00417 IgProfTrace::debugDump(void)
00418 {
00419   fprintf (stderr, "TRACE BUFFER %p:\n", this);
00420   fprintf (stderr, " OPTIONS:   %d\n", options_);
00421   fprintf (stderr, " RESTABLE:  %p\n", restable_);
00422   fprintf (stderr, " CALLCACHE: %p\n", callcache_);
00423 
00424   debugDumpStack(stack_, 0);
00425   // debugDumpResources();
00426 }

Generated on Tue Jun 9 17:38:08 2009 for CMSSW by  doxygen 1.5.4