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
00023
00024
00025
00026 if (opts & OptResources)
00027 restable_ = (Resource **) allocateRaw(RESOURCE_HASH*sizeof(Resource *));
00028
00029
00030 callcache_ = (StackCache *) allocateSpace(MAX_DEPTH*sizeof(StackCache));
00031
00032
00033 stack_ = allocate<Stack>();
00034
00035
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
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
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
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
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
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
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
00163 Resource **rlink;
00164 Resource *res = 0;
00165 if (! findResource(rec, rlink, res, rec.def))
00166
00167 return;
00168 else
00169
00170 releaseResource(rlink, res);
00171 }
00172
00173 void
00174 IgProfTrace::acquireResource(Record &rec, Counter *ctr)
00175 {
00176 IGPROF_ASSERT(ctr);
00177
00178
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
00201 releaseResource(rlink, res);
00202 }
00203
00204
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
00229
00230
00231 if (depth < 0)
00232 depth = 0;
00233
00234
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
00246 frame = childStackNode(frame, address);
00247 cache [i].address = address;
00248 cache [i].frame = frame;
00249 valid = 0;
00250 }
00251 }
00252
00253
00254
00255 for (int i = 0; i < nrecs; ++i)
00256 {
00257 Counter **ctr = 0;
00258 Counter *c = 0;
00259
00260
00261 if (recs[i].type & (COUNT | ACQUIRE))
00262 {
00263
00264 ctr = &frame->counters;
00265 while (*ctr && (*ctr)->def != recs[i].def)
00266 ctr = &(*ctr)->next;
00267
00268
00269 c = *ctr;
00270 if (! c || c->def != recs[i].def)
00271 c = initCounter(*ctr, recs[i].def, frame);
00272
00273
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
00286 if (recs[i].type & ACQUIRE)
00287 acquireResource(recs[i], c);
00288
00289
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
00307 Record recs[MERGE_RECS];
00308 void *callstack[MAX_DEPTH+1];
00309
00310 callstack[MAX_DEPTH] = stack_->address;
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
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
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
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
00426 }