tools/trace-malloc/tmreader.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/trace-malloc/tmreader.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,892 @@
     1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +#include <stdio.h>
    1.10 +#include <stdlib.h>
    1.11 +#include <stdint.h>
    1.12 +#include <string.h>
    1.13 +#include <errno.h>      /* XXX push error reporting out to clients? */
    1.14 +#ifndef XP_WIN
    1.15 +#include <unistd.h>
    1.16 +#else
    1.17 +#include <stddef.h>
    1.18 +#endif
    1.19 +#include "prlog.h"
    1.20 +#include "plhash.h"
    1.21 +/* make sure this happens before tmreader.h */
    1.22 +#define PL_ARENA_CONST_ALIGN_MASK 2
    1.23 +#include "plarena.h"
    1.24 +
    1.25 +#include "prnetdb.h"
    1.26 +#include "nsTraceMalloc.h"
    1.27 +#include "tmreader.h"
    1.28 +
    1.29 +#undef  DEBUG_tmreader
    1.30 +
    1.31 +static int accum_byte(FILE *fp, uint32_t *uip)
    1.32 +{
    1.33 +    int c = getc(fp);
    1.34 +    if (c == EOF)
    1.35 +        return 0;
    1.36 +    *uip = (*uip << 8) | c;
    1.37 +    return 1;
    1.38 +}
    1.39 +
    1.40 +static int get_uint32(FILE *fp, uint32_t *uip)
    1.41 +{
    1.42 +    int c;
    1.43 +    uint32_t ui;
    1.44 +
    1.45 +    c = getc(fp);
    1.46 +    if (c == EOF)
    1.47 +        return 0;
    1.48 +    ui = 0;
    1.49 +    if (c & 0x80) {
    1.50 +        c &= 0x7f;
    1.51 +        if (c & 0x40) {
    1.52 +            c &= 0x3f;
    1.53 +            if (c & 0x20) {
    1.54 +                c &= 0x1f;
    1.55 +                if (c & 0x10) {
    1.56 +                    if (!accum_byte(fp, &ui))
    1.57 +                        return 0;
    1.58 +                } else {
    1.59 +                    ui = (uint32_t) c;
    1.60 +                }
    1.61 +                if (!accum_byte(fp, &ui))
    1.62 +                    return 0;
    1.63 +            } else {
    1.64 +                ui = (uint32_t) c;
    1.65 +            }
    1.66 +            if (!accum_byte(fp, &ui))
    1.67 +                return 0;
    1.68 +        } else {
    1.69 +            ui = (uint32_t) c;
    1.70 +        }
    1.71 +        if (!accum_byte(fp, &ui))
    1.72 +            return 0;
    1.73 +    } else {
    1.74 +        ui = (uint32_t) c;
    1.75 +    }
    1.76 +    *uip = ui;
    1.77 +    return 1;
    1.78 +}
    1.79 +
    1.80 +static char *get_string(FILE *fp)
    1.81 +{
    1.82 +    char *cp;
    1.83 +    int c;
    1.84 +    static char buf[256];
    1.85 +    static char *bp = buf, *ep = buf + sizeof buf;
    1.86 +    static size_t bsize = sizeof buf;
    1.87 +
    1.88 +    cp = bp;
    1.89 +    do {
    1.90 +        c = getc(fp);
    1.91 +        if (c == EOF)
    1.92 +            return 0;
    1.93 +        if (cp == ep) {
    1.94 +            if (bp == buf) {
    1.95 +                bp = malloc(2 * bsize);
    1.96 +                if (bp)
    1.97 +                    memcpy(bp, buf, bsize);
    1.98 +            } else {
    1.99 +                bp = realloc(bp, 2 * bsize);
   1.100 +            }
   1.101 +            if (!bp)
   1.102 +                return 0;
   1.103 +            cp = bp + bsize;
   1.104 +            bsize *= 2;
   1.105 +            ep = bp + bsize;
   1.106 +        }
   1.107 +        *cp++ = c;
   1.108 +    } while (c != '\0');
   1.109 +    return strdup(bp);
   1.110 +}
   1.111 +
   1.112 +static int get_tmevent(FILE *fp, tmevent *event)
   1.113 +{
   1.114 +    int c;
   1.115 +    char *s;
   1.116 +
   1.117 +    c = getc(fp);
   1.118 +    if (c == EOF)
   1.119 +        return 0;
   1.120 +    event->type = (char) c;
   1.121 +    if (!get_uint32(fp, &event->serial))
   1.122 +        return 0;
   1.123 +    switch (c) {
   1.124 +      case TM_EVENT_LIBRARY:
   1.125 +        s = get_string(fp);
   1.126 +        if (!s)
   1.127 +            return 0;
   1.128 +        event->u.libname = s;
   1.129 +#ifdef DEBUG_tmreader
   1.130 +        fprintf(stderr, "tmevent %c %u libname=\"%s\"\n", event->type, event->serial,
   1.131 +                event->u.libname);
   1.132 +#endif
   1.133 +        break;
   1.134 +
   1.135 +      case TM_EVENT_FILENAME:
   1.136 +        s = get_string(fp);
   1.137 +        if (!s)
   1.138 +            return 0;
   1.139 +        event->u.srcname = s;
   1.140 +#ifdef DEBUG_tmreader
   1.141 +        fprintf(stderr, "tmevent %c %u srcname=\"%s\"\n",
   1.142 +                event->type, event->serial, event->u.srcname);
   1.143 +#endif
   1.144 +        break;
   1.145 +
   1.146 +      case TM_EVENT_METHOD:
   1.147 +        if (!get_uint32(fp, &event->u.method.library))
   1.148 +            return 0;
   1.149 +        if (!get_uint32(fp, &event->u.method.filename))
   1.150 +            return 0;
   1.151 +        if (!get_uint32(fp, &event->u.method.linenumber))
   1.152 +            return 0;
   1.153 +        s = get_string(fp);
   1.154 +        if (!s)
   1.155 +            return 0;
   1.156 +        event->u.method.name = s;
   1.157 +#ifdef DEBUG_tmreader
   1.158 +        fprintf(stderr, "tmevent %c %u library=%u filename=%u linenumber=%u "
   1.159 +                "name=\"%s\"\n",
   1.160 +                event->type, event->serial,
   1.161 +                event->u.method.library, event->u.method.filename,
   1.162 +                event->u.method.linenumber, event->u.method.name);
   1.163 +#endif
   1.164 +        break;
   1.165 +
   1.166 +      case TM_EVENT_CALLSITE:
   1.167 +        if (!get_uint32(fp, &event->u.site.parent))
   1.168 +            return 0;
   1.169 +        if (!get_uint32(fp, &event->u.site.method))
   1.170 +            return 0;
   1.171 +        if (!get_uint32(fp, &event->u.site.offset))
   1.172 +            return 0;
   1.173 +#ifdef DEBUG_tmreader
   1.174 +        fprintf(stderr, "tmevent %c %u parent=%u method=%u offset=%u\n",
   1.175 +                event->type, event->serial,
   1.176 +                event->u.site.parent, event->u.site.method,
   1.177 +                event->u.site.offset);
   1.178 +#endif
   1.179 +        break;
   1.180 +
   1.181 +      case TM_EVENT_MALLOC:
   1.182 +      case TM_EVENT_CALLOC:
   1.183 +      case TM_EVENT_FREE:
   1.184 +        if (!get_uint32(fp, &event->u.alloc.interval))
   1.185 +            return 0;
   1.186 +        if (!get_uint32(fp, &event->u.alloc.cost))
   1.187 +            return 0;
   1.188 +        if (!get_uint32(fp, &event->u.alloc.ptr))
   1.189 +            return 0;
   1.190 +        if (!get_uint32(fp, &event->u.alloc.size))
   1.191 +            return 0;
   1.192 +        event->u.alloc.oldserial = 0;
   1.193 +        event->u.alloc.oldptr = 0;
   1.194 +        event->u.alloc.oldsize = 0;
   1.195 +#ifdef DEBUG_tmreader
   1.196 +        fprintf(stderr, "tmevent %c %u interval=%u cost=%u ptr=0x%x size=%u\n",
   1.197 +                event->type, event->serial,
   1.198 +                event->u.alloc.interval, event->u.alloc.cost,
   1.199 +                event->u.alloc.ptr, event->u.alloc.size);
   1.200 +#endif
   1.201 +#if defined(DEBUG_dp)
   1.202 +        if (c == TM_EVENT_MALLOC)
   1.203 +            printf("%d malloc %d 0x%p\n", event->u.alloc.cost,
   1.204 +                   event->u.alloc.size, event->u.alloc.ptr);
   1.205 +        else if (c == TM_EVENT_CALLOC)
   1.206 +            printf("%d calloc %d 0x%p\n", event->u.alloc.cost,
   1.207 +                   event->u.alloc.size, event->u.alloc.ptr);
   1.208 +        else
   1.209 +            printf("%d free %d 0x%p\n", event->u.alloc.cost,
   1.210 +                   event->u.alloc.size, event->u.alloc.ptr);
   1.211 +#endif
   1.212 +        break;
   1.213 +
   1.214 +      case TM_EVENT_REALLOC:
   1.215 +        if (!get_uint32(fp, &event->u.alloc.interval))
   1.216 +            return 0;
   1.217 +        if (!get_uint32(fp, &event->u.alloc.cost))
   1.218 +            return 0;
   1.219 +        if (!get_uint32(fp, &event->u.alloc.ptr))
   1.220 +            return 0;
   1.221 +        if (!get_uint32(fp, &event->u.alloc.size))
   1.222 +            return 0;
   1.223 +        if (!get_uint32(fp, &event->u.alloc.oldserial))
   1.224 +            return 0;
   1.225 +        if (!get_uint32(fp, &event->u.alloc.oldptr))
   1.226 +            return 0;
   1.227 +        if (!get_uint32(fp, &event->u.alloc.oldsize))
   1.228 +            return 0;
   1.229 +#ifdef DEBUG_tmreader
   1.230 +        fprintf(stderr, "tmevent %c %u interval=%u cost=%u ptr=0x%x size=%u "
   1.231 +                "oldserial=%u oldptr=0x%x oldsize=%u\n",
   1.232 +                event->type, event->serial,
   1.233 +                event->u.alloc.interval, event->u.alloc.cost,
   1.234 +                event->u.alloc.ptr, event->u.alloc.size,
   1.235 +                event->u.alloc.oldserial, event->u.alloc.oldptr,
   1.236 +                event->u.alloc.oldsize);
   1.237 +#endif
   1.238 +#if defined(DEBUG_dp)
   1.239 +        printf("%d realloc %d 0x%p %d\n", event->u.alloc.cost,
   1.240 +               event->u.alloc.size, event->u.alloc.ptr, event->u.alloc.oldsize);
   1.241 +#endif
   1.242 +        break;
   1.243 +
   1.244 +      case TM_EVENT_STATS:
   1.245 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_maxstack))
   1.246 +            return 0;
   1.247 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_maxdepth))
   1.248 +            return 0;
   1.249 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_parents))
   1.250 +            return 0;
   1.251 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_maxkids))
   1.252 +            return 0;
   1.253 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_kidhits))
   1.254 +            return 0;
   1.255 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_kidmisses))
   1.256 +            return 0;
   1.257 +        if (!get_uint32(fp, &event->u.stats.tmstats.calltree_kidsteps))
   1.258 +            return 0;
   1.259 +        if (!get_uint32(fp, &event->u.stats.tmstats.callsite_recurrences))
   1.260 +            return 0;
   1.261 +        if (!get_uint32(fp, &event->u.stats.tmstats.backtrace_calls))
   1.262 +            return 0;
   1.263 +        if (!get_uint32(fp, &event->u.stats.tmstats.backtrace_failures))
   1.264 +            return 0;
   1.265 +        if (!get_uint32(fp, &event->u.stats.tmstats.btmalloc_failures))
   1.266 +            return 0;
   1.267 +        if (!get_uint32(fp, &event->u.stats.tmstats.dladdr_failures))
   1.268 +            return 0;
   1.269 +        if (!get_uint32(fp, &event->u.stats.tmstats.malloc_calls))
   1.270 +            return 0;
   1.271 +        if (!get_uint32(fp, &event->u.stats.tmstats.malloc_failures))
   1.272 +            return 0;
   1.273 +        if (!get_uint32(fp, &event->u.stats.tmstats.calloc_calls))
   1.274 +            return 0;
   1.275 +        if (!get_uint32(fp, &event->u.stats.tmstats.calloc_failures))
   1.276 +            return 0;
   1.277 +        if (!get_uint32(fp, &event->u.stats.tmstats.realloc_calls))
   1.278 +            return 0;
   1.279 +        if (!get_uint32(fp, &event->u.stats.tmstats.realloc_failures))
   1.280 +            return 0;
   1.281 +        if (!get_uint32(fp, &event->u.stats.tmstats.free_calls))
   1.282 +            return 0;
   1.283 +        if (!get_uint32(fp, &event->u.stats.tmstats.null_free_calls))
   1.284 +            return 0;
   1.285 +        if (!get_uint32(fp, &event->u.stats.calltree_maxkids_parent))
   1.286 +            return 0;
   1.287 +        if (!get_uint32(fp, &event->u.stats.calltree_maxstack_top))
   1.288 +            return 0;
   1.289 +#ifdef DEBUG_tmreader
   1.290 +        fprintf(stderr, "tmevent %c %u\n", event->type, event->serial);
   1.291 +#endif
   1.292 +        break;
   1.293 +      default:
   1.294 +        fprintf(stderr, "Unknown event type 0x%x\n", (unsigned int)event->type);
   1.295 +        return 0;
   1.296 +    }
   1.297 +    return 1;
   1.298 +}
   1.299 +
   1.300 +static void *arena_alloc(void* pool, size_t size)
   1.301 +{
   1.302 +    PLArenaPool* arena = (PLArenaPool*)pool;
   1.303 +    void* result;
   1.304 +    PL_ARENA_ALLOCATE(result, arena, size);
   1.305 +    memset(result, 0, size);
   1.306 +    return result;
   1.307 +}
   1.308 +
   1.309 +static void *generic_alloctable(void *pool, size_t size)
   1.310 +{
   1.311 +    return arena_alloc(pool, size);
   1.312 +}
   1.313 +
   1.314 +static void generic_freetable(void *pool, void *item)
   1.315 +{
   1.316 +    /* do nothing - arena-allocated */
   1.317 +}
   1.318 +
   1.319 +static PLHashEntry *filename_allocentry(void *pool, const void *key)
   1.320 +{
   1.321 +    return (PLHashEntry*)arena_alloc(pool, sizeof(PLHashEntry));
   1.322 +}
   1.323 +
   1.324 +static PLHashEntry *callsite_allocentry(void *pool, const void *key)
   1.325 +{
   1.326 +    return (PLHashEntry*)arena_alloc(pool, sizeof(tmcallsite));
   1.327 +}
   1.328 +
   1.329 +static void init_graphnode(tmgraphnode* node)
   1.330 +{
   1.331 +    node->in = node->out = NULL;
   1.332 +    node->up = node->down = node->next = NULL;
   1.333 +    node->low = 0;
   1.334 +    node->allocs.bytes.direct = node->allocs.bytes.total = 0;
   1.335 +    node->allocs.calls.direct = node->allocs.calls.total = 0;
   1.336 +    node->frees.bytes.direct = node->frees.bytes.total = 0;
   1.337 +    node->frees.calls.direct = node->frees.calls.total = 0;
   1.338 +    node->sqsum = 0;
   1.339 +    node->sort = -1;
   1.340 +}
   1.341 +
   1.342 +static PLHashEntry *graphnode_allocentry(void *pool, const void *key)
   1.343 +{
   1.344 +    tmgraphnode* node = (tmgraphnode*)arena_alloc(pool, sizeof(tmgraphnode));
   1.345 +    if (!node)
   1.346 +        return NULL;
   1.347 +    init_graphnode(node);
   1.348 +    return &node->entry;
   1.349 +}
   1.350 +
   1.351 +static void init_method(tmmethodnode *node)
   1.352 +{
   1.353 +    node->graphnode.in = node->graphnode.out = NULL;
   1.354 +    node->graphnode.up = node->graphnode.down = node->graphnode.next = NULL;
   1.355 +    node->graphnode.low = 0;
   1.356 +    node->graphnode.allocs.bytes.direct = node->graphnode.allocs.bytes.total = 0;
   1.357 +    node->graphnode.allocs.calls.direct = node->graphnode.allocs.calls.total = 0;
   1.358 +    node->graphnode.frees.bytes.direct = node->graphnode.frees.bytes.total = 0;
   1.359 +    node->graphnode.frees.calls.direct = node->graphnode.frees.calls.total = 0;
   1.360 +    node->graphnode.sqsum = 0;
   1.361 +    node->graphnode.sort = -1;
   1.362 +    node->sourcefile = NULL;
   1.363 +    node->linenumber = 0;
   1.364 +}
   1.365 +
   1.366 +static PLHashEntry *method_allocentry(void *pool, const void *key)
   1.367 +{
   1.368 +    tmmethodnode *node =
   1.369 +        (tmmethodnode*) arena_alloc(pool, sizeof(tmmethodnode));
   1.370 +    if (!node)
   1.371 +        return NULL;
   1.372 +    init_method(node);
   1.373 +    return &node->graphnode.entry;
   1.374 +}
   1.375 +
   1.376 +static void graphnode_freeentry(void *pool, PLHashEntry *he, unsigned flag)
   1.377 +{
   1.378 +    /* Always free the value, which points to a strdup'd string. */
   1.379 +    free(he->value);
   1.380 +#if 0                           /* using arenas now, no freeing! */
   1.381 +    /* Free the whole thing if we're told to. */
   1.382 +    if (flag == HT_FREE_ENTRY)
   1.383 +        free((void*) he);
   1.384 +#endif
   1.385 +}
   1.386 +
   1.387 +static void component_freeentry(void *pool, PLHashEntry *he, unsigned flag)
   1.388 +{
   1.389 +    if (flag == HT_FREE_ENTRY) {
   1.390 +        tmgraphnode *comp = (tmgraphnode*) he;
   1.391 +
   1.392 +        /* Free the key, which was strdup'd (N.B. value also points to it). */
   1.393 +        free((void*) tmcomponent_name(comp));
   1.394 +#if 0                           /* using arenas now, no freeing! */
   1.395 +        free((void*) comp);
   1.396 +#endif
   1.397 +    }
   1.398 +}
   1.399 +
   1.400 +static PLHashAllocOps filename_hashallocops = {
   1.401 +    generic_alloctable,     generic_freetable,
   1.402 +    filename_allocentry,    graphnode_freeentry
   1.403 +};
   1.404 +
   1.405 +static PLHashAllocOps callsite_hashallocops = {
   1.406 +    generic_alloctable,     generic_freetable,
   1.407 +    callsite_allocentry,    graphnode_freeentry
   1.408 +};
   1.409 +
   1.410 +static PLHashAllocOps graphnode_hashallocops = {
   1.411 +    generic_alloctable,     generic_freetable,
   1.412 +    graphnode_allocentry,   graphnode_freeentry
   1.413 +};
   1.414 +
   1.415 +static PLHashAllocOps method_hashallocops = {
   1.416 +    generic_alloctable,     generic_freetable,
   1.417 +    method_allocentry,      graphnode_freeentry
   1.418 +};
   1.419 +
   1.420 +static PLHashAllocOps component_hashallocops = {
   1.421 +    generic_alloctable,     generic_freetable,
   1.422 +    graphnode_allocentry,   component_freeentry
   1.423 +};
   1.424 +
   1.425 +static PLHashNumber hash_serial(const void *key)
   1.426 +{
   1.427 +    return (PLHashNumber) key;
   1.428 +}
   1.429 +
   1.430 +tmreader *tmreader_new(const char *program, void *data)
   1.431 +{
   1.432 +    tmreader *tmr;
   1.433 +
   1.434 +    tmr = calloc(1, sizeof *tmr);
   1.435 +    if (!tmr)
   1.436 +        return NULL;
   1.437 +    tmr->program = program;
   1.438 +    tmr->data = data;
   1.439 +    PL_INIT_ARENA_POOL(&tmr->arena, "TMReader", 256*1024);
   1.440 +
   1.441 +    tmr->libraries = PL_NewHashTable(100, hash_serial, PL_CompareValues,
   1.442 +                                     PL_CompareStrings, &graphnode_hashallocops,
   1.443 +                                     &tmr->arena);
   1.444 +    tmr->filenames = PL_NewHashTable(100, hash_serial, PL_CompareValues,
   1.445 +                                     PL_CompareStrings, &filename_hashallocops,
   1.446 +                                     &tmr->arena);
   1.447 +    tmr->components = PL_NewHashTable(10000, PL_HashString, PL_CompareStrings,
   1.448 +                                      PL_CompareValues, &component_hashallocops,
   1.449 +                                      &tmr->arena);
   1.450 +    tmr->methods = PL_NewHashTable(10000, hash_serial, PL_CompareValues,
   1.451 +                                   PL_CompareStrings, &method_hashallocops,
   1.452 +                                   &tmr->arena);
   1.453 +    tmr->callsites = PL_NewHashTable(200000, hash_serial, PL_CompareValues,
   1.454 +                                     PL_CompareValues, &callsite_hashallocops,
   1.455 +                                     &tmr->arena);
   1.456 +    tmr->calltree_root.entry.value = (void*) strdup("root");
   1.457 +
   1.458 +    if (!tmr->libraries || !tmr->components || !tmr->methods ||
   1.459 +        !tmr->callsites || !tmr->calltree_root.entry.value ||
   1.460 +        !tmr->filenames) {
   1.461 +        tmreader_destroy(tmr);
   1.462 +        return NULL;
   1.463 +    }
   1.464 +    return tmr;
   1.465 +}
   1.466 +
   1.467 +void tmreader_destroy(tmreader *tmr)
   1.468 +{
   1.469 +    if (tmr->libraries)
   1.470 +        PL_HashTableDestroy(tmr->libraries);
   1.471 +    if (tmr->filenames)
   1.472 +        PL_HashTableDestroy(tmr->filenames);
   1.473 +    if (tmr->components)
   1.474 +        PL_HashTableDestroy(tmr->components);
   1.475 +    if (tmr->methods)
   1.476 +        PL_HashTableDestroy(tmr->methods);
   1.477 +    if (tmr->callsites)
   1.478 +        PL_HashTableDestroy(tmr->callsites);
   1.479 +    PL_FinishArenaPool(&tmr->arena);
   1.480 +    free(tmr);
   1.481 +}
   1.482 +
   1.483 +int tmreader_eventloop(tmreader *tmr, const char *filename,
   1.484 +                       tmeventhandler eventhandler)
   1.485 +{
   1.486 +    FILE *fp;
   1.487 +    char buf[NS_TRACE_MALLOC_MAGIC_SIZE];
   1.488 +    tmevent event;
   1.489 +    static const char magic[] = NS_TRACE_MALLOC_MAGIC;
   1.490 +
   1.491 +    if (strcmp(filename, "-") == 0) {
   1.492 +        fp = stdin;
   1.493 +    } else {
   1.494 +#if defined(XP_WIN32)
   1.495 +        fp = fopen(filename, "rb");
   1.496 +#else
   1.497 +        fp = fopen(filename, "r");
   1.498 +#endif
   1.499 +        if (!fp) {
   1.500 +            fprintf(stderr, "%s: can't open %s: %s.\n",
   1.501 +                    tmr->program, filename, strerror(errno));
   1.502 +            return 0;
   1.503 +        }
   1.504 +    }
   1.505 +
   1.506 +    if (read(fileno(fp), buf, sizeof buf) != sizeof buf ||
   1.507 +        strncmp(buf, magic, sizeof buf) != 0) {
   1.508 +        fprintf(stderr, "%s: bad magic string %s at start of %s.\n",
   1.509 +                tmr->program, buf, filename);
   1.510 +        fprintf(stderr, "either the data file is out of date,\nor your tools are out of date.\n");
   1.511 +        return 0;
   1.512 +    }
   1.513 +
   1.514 +    /* Read in ticks per second. Used to convert platform specific intervals to time values */
   1.515 +    if (read(fileno(fp), &tmr->ticksPerSec, sizeof tmr->ticksPerSec) != sizeof tmr->ticksPerSec) {
   1.516 +        fprintf(stderr, "%s: Cannot read ticksPerSec. Log file read error.\n",
   1.517 +                tmr->program);
   1.518 +        return 0;
   1.519 +    }
   1.520 +    tmr->ticksPerSec = PR_ntohl(tmr->ticksPerSec);
   1.521 +#ifdef DEBUG_dp
   1.522 +    printf("DEBUG: ticks per sec = %d\n", tmr->ticksPerSec);
   1.523 +#endif
   1.524 +    while (get_tmevent(fp, &event)) {
   1.525 +        switch (event.type) {
   1.526 +          case TM_EVENT_LIBRARY: {
   1.527 +            const void *key;
   1.528 +            PLHashNumber hash;
   1.529 +            PLHashEntry **hep, *he;
   1.530 +
   1.531 +            key = (const void*) (uintptr_t) event.serial;
   1.532 +            hash = hash_serial(key);
   1.533 +            hep = PL_HashTableRawLookup(tmr->libraries, hash, key);
   1.534 +            he = *hep;
   1.535 +            PR_ASSERT(!he);
   1.536 +            if (he) exit(2);
   1.537 +
   1.538 +            he = PL_HashTableRawAdd(tmr->libraries, hep, hash, key,
   1.539 +                                    event.u.libname);
   1.540 +            if (!he) {
   1.541 +                perror(tmr->program);
   1.542 +                return -1;
   1.543 +            }
   1.544 +            break;
   1.545 +          }
   1.546 +
   1.547 +          case TM_EVENT_FILENAME: {
   1.548 +            const void *key;
   1.549 +            PLHashNumber hash;
   1.550 +            PLHashEntry **hep, *he;
   1.551 +
   1.552 +            key = (const void*) (uintptr_t) event.serial;
   1.553 +            hash = hash_serial(key);
   1.554 +            hep = PL_HashTableRawLookup(tmr->filenames, hash, key);
   1.555 +            he = *hep;
   1.556 +            PR_ASSERT(!he);
   1.557 +            if (he) exit(2);
   1.558 +
   1.559 +            he = PL_HashTableRawAdd(tmr->filenames, hep, hash, key,
   1.560 +                                    event.u.srcname);
   1.561 +            if (!he) {
   1.562 +                perror(tmr->program);
   1.563 +                return -1;
   1.564 +            }
   1.565 +            break;
   1.566 +          }
   1.567 +
   1.568 +          case TM_EVENT_METHOD: {
   1.569 +            const void *key, *sourcekey;
   1.570 +            PLHashNumber hash, sourcehash;
   1.571 +            PLHashEntry **hep, *he, **sourcehep, *sourcehe;
   1.572 +            char *name, *head, *mark, save;
   1.573 +            tmgraphnode *comp, *lib;
   1.574 +            tmmethodnode *meth;
   1.575 +
   1.576 +            key = (const void*) (uintptr_t) event.serial;
   1.577 +            hash = hash_serial(key);
   1.578 +            hep = PL_HashTableRawLookup(tmr->methods, hash, key);
   1.579 +            he = *hep;
   1.580 +            PR_ASSERT(!he);
   1.581 +            if (he) exit(2);
   1.582 +
   1.583 +            name = event.u.method.name;
   1.584 +            he = PL_HashTableRawAdd(tmr->methods, hep, hash, key, name);
   1.585 +            if (!he) {
   1.586 +                perror(tmr->program);
   1.587 +                return -1;
   1.588 +            }
   1.589 +            meth = (tmmethodnode*) he;
   1.590 +
   1.591 +            meth->linenumber = event.u.method.linenumber;
   1.592 +            sourcekey = (const void*) (uintptr_t) event.u.method.filename;
   1.593 +            sourcehash = hash_serial(sourcekey);
   1.594 +            sourcehep = PL_HashTableRawLookup(tmr->filenames, sourcehash, sourcekey);
   1.595 +            sourcehe = *sourcehep;
   1.596 +            meth->sourcefile = filename_name(sourcehe);
   1.597 +
   1.598 +            head = name;
   1.599 +            mark = strchr(name, ':');
   1.600 +            if (!mark) {
   1.601 +                mark = name;
   1.602 +                while (*mark != '\0' && *mark == '_')
   1.603 +                    mark++;
   1.604 +                head = mark;
   1.605 +                mark = strchr(head, '_');
   1.606 +                if (!mark) {
   1.607 +                    mark = strchr(head, '+');
   1.608 +                    if (!mark)
   1.609 +                        mark = head + strlen(head);
   1.610 +                }
   1.611 +            }
   1.612 +
   1.613 +            save = *mark;
   1.614 +            *mark = '\0';
   1.615 +            hash = PL_HashString(head);
   1.616 +            hep = PL_HashTableRawLookup(tmr->components, hash, head);
   1.617 +            he = *hep;
   1.618 +            if (he) {
   1.619 +                comp = (tmgraphnode*) he;
   1.620 +            } else {
   1.621 +                head = strdup(head);
   1.622 +                if (head) {
   1.623 +                    he = PL_HashTableRawAdd(tmr->components, hep, hash, head,
   1.624 +                                            head);
   1.625 +                }
   1.626 +                if (!he) {
   1.627 +                    perror(tmr->program);
   1.628 +                    return -1;
   1.629 +                }
   1.630 +                comp = (tmgraphnode*) he;
   1.631 +
   1.632 +                key = (const void*) (uintptr_t) event.u.method.library;
   1.633 +                hash = hash_serial(key);
   1.634 +                lib = (tmgraphnode*)
   1.635 +                      *PL_HashTableRawLookup(tmr->libraries, hash, key);
   1.636 +                if (lib) {
   1.637 +                    comp->up = lib;
   1.638 +                    comp->next = lib->down;
   1.639 +                    lib->down = comp;
   1.640 +                }
   1.641 +            }
   1.642 +            *mark = save;
   1.643 +
   1.644 +            meth->graphnode.up = comp;
   1.645 +            meth->graphnode.next = comp->down;
   1.646 +            comp->down = &(meth->graphnode);
   1.647 +            break;
   1.648 +          }
   1.649 +
   1.650 +          case TM_EVENT_CALLSITE: {
   1.651 +            const void *key, *mkey;
   1.652 +            PLHashNumber hash, mhash;
   1.653 +            PLHashEntry **hep, *he;
   1.654 +            tmcallsite *site, *parent;
   1.655 +            tmmethodnode *meth;
   1.656 +
   1.657 +            key = (const void*) (uintptr_t) event.serial;
   1.658 +            hash = hash_serial(key);
   1.659 +            hep = PL_HashTableRawLookup(tmr->callsites, hash, key);
   1.660 +            he = *hep;
   1.661 +
   1.662 +            /* there should not be an entry here! */
   1.663 +            PR_ASSERT(!he);
   1.664 +            if (he) exit(2);
   1.665 +
   1.666 +            if (event.u.site.parent == 0) {
   1.667 +                parent = &tmr->calltree_root;
   1.668 +            } else {
   1.669 +                parent = tmreader_callsite(tmr, event.u.site.parent);
   1.670 +                if (!parent) {
   1.671 +                    fprintf(stderr, "%s: no parent for %lu (%lu)!\n",
   1.672 +                            tmr->program, (unsigned long) event.serial,
   1.673 +                            (unsigned long) event.u.site.parent);
   1.674 +                    continue;
   1.675 +                }
   1.676 +            }
   1.677 +
   1.678 +            he = PL_HashTableRawAdd(tmr->callsites, hep, hash, key, NULL);
   1.679 +            if (!he) {
   1.680 +                perror(tmr->program);
   1.681 +                return -1;
   1.682 +            }
   1.683 +
   1.684 +            site = (tmcallsite*) he;
   1.685 +            site->parent = parent;
   1.686 +            site->siblings = parent->kids;
   1.687 +            parent->kids = site;
   1.688 +            site->kids = NULL;
   1.689 +
   1.690 +            mkey = (const void*) (uintptr_t) event.u.site.method;
   1.691 +            mhash = hash_serial(mkey);
   1.692 +            meth = (tmmethodnode*)
   1.693 +                   *PL_HashTableRawLookup(tmr->methods, mhash, mkey);
   1.694 +            site->method = meth;
   1.695 +            site->offset = event.u.site.offset;
   1.696 +            site->allocs.bytes.direct = site->allocs.bytes.total = 0;
   1.697 +            site->allocs.calls.direct = site->allocs.calls.total = 0;
   1.698 +            site->frees.bytes.direct = site->frees.bytes.total = 0;
   1.699 +            site->frees.calls.direct = site->frees.calls.total = 0;
   1.700 +            break;
   1.701 +          }
   1.702 +
   1.703 +          case TM_EVENT_MALLOC:
   1.704 +          case TM_EVENT_CALLOC:
   1.705 +          case TM_EVENT_REALLOC: {
   1.706 +            tmcallsite *site;
   1.707 +            uint32_t size, oldsize;
   1.708 +            double delta, sqdelta, sqszdelta = 0;
   1.709 +            tmgraphnode *comp, *lib;
   1.710 +            tmmethodnode *meth;
   1.711 +
   1.712 +            site = tmreader_callsite(tmr, event.serial);
   1.713 +            if (!site) {
   1.714 +                fprintf(stderr, "%s: no callsite for '%c' (%lu)!\n",
   1.715 +                        tmr->program, event.type, (unsigned long) event.serial);
   1.716 +                continue;
   1.717 +            }
   1.718 +
   1.719 +            size = event.u.alloc.size;
   1.720 +            oldsize = event.u.alloc.oldsize;
   1.721 +            delta = (double)size - (double)oldsize;
   1.722 +            site->allocs.bytes.direct += (unsigned long)delta;
   1.723 +            if (event.type != TM_EVENT_REALLOC)
   1.724 +                site->allocs.calls.direct++;
   1.725 +            meth = site->method;
   1.726 +            if (meth) {
   1.727 +                meth->graphnode.allocs.bytes.direct += (unsigned long)delta;
   1.728 +                sqdelta = delta * delta;
   1.729 +                if (event.type == TM_EVENT_REALLOC) {
   1.730 +                    sqszdelta = ((double)size * size)
   1.731 +                              - ((double)oldsize * oldsize);
   1.732 +                    meth->graphnode.sqsum += sqszdelta;
   1.733 +                } else {
   1.734 +                    meth->graphnode.sqsum += sqdelta;
   1.735 +                    meth->graphnode.allocs.calls.direct++;
   1.736 +                }
   1.737 +                comp = meth->graphnode.up;
   1.738 +                if (comp) {
   1.739 +                    comp->allocs.bytes.direct += (unsigned long)delta;
   1.740 +                    if (event.type == TM_EVENT_REALLOC) {
   1.741 +                        comp->sqsum += sqszdelta;
   1.742 +                    } else {
   1.743 +                        comp->sqsum += sqdelta;
   1.744 +                        comp->allocs.calls.direct++;
   1.745 +                    }
   1.746 +                    lib = comp->up;
   1.747 +                    if (lib) {
   1.748 +                        lib->allocs.bytes.direct += (unsigned long)delta;
   1.749 +                        if (event.type == TM_EVENT_REALLOC) {
   1.750 +                            lib->sqsum += sqszdelta;
   1.751 +                        } else {
   1.752 +                            lib->sqsum += sqdelta;
   1.753 +                            lib->allocs.calls.direct++;
   1.754 +                        }
   1.755 +                    }
   1.756 +                }
   1.757 +            }
   1.758 +            break;
   1.759 +          }
   1.760 +
   1.761 +          case TM_EVENT_FREE: {
   1.762 +            tmcallsite *site;
   1.763 +            uint32_t size;
   1.764 +            tmgraphnode *comp, *lib;
   1.765 +            tmmethodnode *meth;
   1.766 +
   1.767 +            site = tmreader_callsite(tmr, event.serial);
   1.768 +            if (!site) {
   1.769 +                fprintf(stderr, "%s: no callsite for '%c' (%lu)!\n",
   1.770 +                        tmr->program, event.type, (unsigned long) event.serial);
   1.771 +                continue;
   1.772 +            }
   1.773 +            size = event.u.alloc.size;
   1.774 +            site->frees.bytes.direct += size;
   1.775 +            site->frees.calls.direct++;
   1.776 +            meth = site->method;
   1.777 +            if (meth) {
   1.778 +                meth->graphnode.frees.bytes.direct += size;
   1.779 +                meth->graphnode.frees.calls.direct++;
   1.780 +                comp = meth->graphnode.up;
   1.781 +                if (comp) {
   1.782 +                    comp->frees.bytes.direct += size;
   1.783 +                    comp->frees.calls.direct++;
   1.784 +                    lib = comp->up;
   1.785 +                    if (lib) {
   1.786 +                        lib->frees.bytes.direct += size;
   1.787 +                        lib->frees.calls.direct++;
   1.788 +                    }
   1.789 +                }
   1.790 +            }
   1.791 +            break;
   1.792 +          }
   1.793 +
   1.794 +          case TM_EVENT_STATS:
   1.795 +            break;
   1.796 +        }
   1.797 +
   1.798 +        eventhandler(tmr, &event);
   1.799 +    }
   1.800 +
   1.801 +    return 1;
   1.802 +}
   1.803 +
   1.804 +tmgraphnode *tmreader_library(tmreader *tmr, uint32_t serial)
   1.805 +{
   1.806 +    const void *key;
   1.807 +    PLHashNumber hash;
   1.808 +
   1.809 +    key = (const void*) (uintptr_t) serial;
   1.810 +    hash = hash_serial(key);
   1.811 +    return (tmgraphnode*) *PL_HashTableRawLookup(tmr->libraries, hash, key);
   1.812 +}
   1.813 +
   1.814 +tmgraphnode *tmreader_filename(tmreader *tmr, uint32_t serial)
   1.815 +{
   1.816 +    const void *key;
   1.817 +    PLHashNumber hash;
   1.818 +
   1.819 +    key = (const void*) (uintptr_t) serial;
   1.820 +    hash = hash_serial(key);
   1.821 +    return (tmgraphnode*) *PL_HashTableRawLookup(tmr->filenames, hash, key);
   1.822 +}
   1.823 +
   1.824 +tmgraphnode *tmreader_component(tmreader *tmr, const char *name)
   1.825 +{
   1.826 +    PLHashNumber hash;
   1.827 +
   1.828 +    hash = PL_HashString(name);
   1.829 +    return (tmgraphnode*) *PL_HashTableRawLookup(tmr->components, hash, name);
   1.830 +}
   1.831 +
   1.832 +tmmethodnode *tmreader_method(tmreader *tmr, uint32_t serial)
   1.833 +{
   1.834 +    const void *key;
   1.835 +    PLHashNumber hash;
   1.836 +
   1.837 +    key = (const void*) (uintptr_t) serial;
   1.838 +    hash = hash_serial(key);
   1.839 +    return (tmmethodnode*) *PL_HashTableRawLookup(tmr->methods, hash, key);
   1.840 +}
   1.841 +
   1.842 +tmcallsite *tmreader_callsite(tmreader *tmr, uint32_t serial)
   1.843 +{
   1.844 +    const void *key;
   1.845 +    PLHashNumber hash;
   1.846 +
   1.847 +    key = (const void*) (uintptr_t) serial;
   1.848 +    hash = hash_serial(key);
   1.849 +    return (tmcallsite*) *PL_HashTableRawLookup(tmr->callsites, hash, key);
   1.850 +}
   1.851 +
   1.852 +int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, tmcallsite *site)
   1.853 +{
   1.854 +    tmgraphlink *outlink;
   1.855 +    tmgraphedge *edge;
   1.856 +
   1.857 +    for (outlink = from->out; outlink; outlink = outlink->next) {
   1.858 +        if (outlink->node == to) {
   1.859 +            /*
   1.860 +             * Say the stack looks like this: ... => JS => js => JS => js.
   1.861 +             * We must avoid overcounting JS=>js because the first edge total
   1.862 +             * includes the second JS=>js edge's total (which is because the
   1.863 +             * lower site's total includes all its kids' totals).
   1.864 +             */
   1.865 +            edge = TM_LINK_TO_EDGE(outlink, TM_EDGE_OUT_LINK);
   1.866 +            if (!to->low || to->low < from->low) {
   1.867 +                /* Add the direct and total counts to edge->allocs. */
   1.868 +                edge->allocs.bytes.direct += site->allocs.bytes.direct;
   1.869 +                edge->allocs.bytes.total += site->allocs.bytes.total;
   1.870 +                edge->allocs.calls.direct += site->allocs.calls.direct;
   1.871 +                edge->allocs.calls.total += site->allocs.calls.total;
   1.872 +
   1.873 +                /* Now update the free counts. */
   1.874 +                edge->frees.bytes.direct += site->frees.bytes.direct;
   1.875 +                edge->frees.bytes.total += site->frees.bytes.total;
   1.876 +                edge->frees.calls.direct += site->frees.calls.direct;
   1.877 +                edge->frees.calls.total += site->frees.calls.total;
   1.878 +            }
   1.879 +            return 1;
   1.880 +        }
   1.881 +    }
   1.882 +
   1.883 +    edge = (tmgraphedge*) malloc(sizeof(tmgraphedge));
   1.884 +    if (!edge)
   1.885 +        return 0;
   1.886 +    edge->links[TM_EDGE_OUT_LINK].node = to;
   1.887 +    edge->links[TM_EDGE_OUT_LINK].next = from->out;
   1.888 +    from->out = &edge->links[TM_EDGE_OUT_LINK];
   1.889 +    edge->links[TM_EDGE_IN_LINK].node = from;
   1.890 +    edge->links[TM_EDGE_IN_LINK].next = to->in;
   1.891 +    to->in = &edge->links[TM_EDGE_IN_LINK];
   1.892 +    edge->allocs = site->allocs;
   1.893 +    edge->frees = site->frees;
   1.894 +    return 1;
   1.895 +}

mercurial