Home | History | Annotate | Download | only in cachegrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- A program that merges multiple cachegrind output files.      ---*/
      4 /*---                                                   cg_merge.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8   This file is part of Cachegrind, a Valgrind tool for cache
      9   profiling programs.
     10 
     11   Copyright (C) 2002-2013 Nicholas Nethercote
     12      njn (at) valgrind.org
     13 
     14   AVL tree code derived from
     15   ANSI C Library for maintainance of AVL Balanced Trees
     16   (C) 2000 Daniel Nagy, Budapest University of Technology and Economics
     17   Released under GNU General Public License (GPL) version 2
     18 
     19   This program is free software; you can redistribute it and/or
     20   modify it under the terms of the GNU General Public License as
     21   published by the Free Software Foundation; either version 2 of the
     22   License, or (at your option) any later version.
     23 
     24   This program is distributed in the hope that it will be useful, but
     25   WITHOUT ANY WARRANTY; without even the implied warranty of
     26   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     27   General Public License for more details.
     28 
     29   You should have received a copy of the GNU General Public License
     30   along with this program; if not, write to the Free Software
     31   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     32   02111-1307, USA.
     33 
     34   The GNU General Public License is contained in the file COPYING.
     35 */
     36 
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <assert.h>
     40 #include <string.h>
     41 #include <ctype.h>
     42 
     43 typedef  signed long   Word;
     44 typedef  unsigned long UWord;
     45 typedef  unsigned char Bool;
     46 #define True ((Bool)1)
     47 #define False ((Bool)0)
     48 typedef  signed int    Int;
     49 typedef  unsigned int  UInt;
     50 typedef  unsigned long long int ULong;
     51 typedef  signed char   Char;
     52 typedef  size_t        SizeT;
     53 
     54 
     55 //------------------------------------------------------------------//
     56 //---                           WordFM                           ---//
     57 //---                      Public interface                      ---//
     58 //------------------------------------------------------------------//
     59 
     60 typedef  struct _WordFM  WordFM; /* opaque */
     61 
     62 /* Initialise a WordFM */
     63 void initFM ( WordFM* t,
     64               void*   (*alloc_nofail)( SizeT ),
     65               void    (*dealloc)(void*),
     66               Word    (*kCmp)(Word,Word) );
     67 
     68 /* Allocate and initialise a WordFM */
     69 WordFM* newFM( void* (*alloc_nofail)( SizeT ),
     70                void  (*dealloc)(void*),
     71                Word  (*kCmp)(Word,Word) );
     72 
     73 /* Free up the FM.  If kFin is non-NULL, it is applied to keys
     74    before the FM is deleted; ditto with vFin for vals. */
     75 void deleteFM ( WordFM*, void(*kFin)(Word), void(*vFin)(Word) );
     76 
     77 /* Add (k,v) to fm.  If a binding for k already exists, it is updated
     78    to map to this new v.  In that case we should really return the
     79    previous v so that caller can finalise it.  Oh well. */
     80 void addToFM ( WordFM* fm, Word k, Word v );
     81 
     82 // Delete key from fm, returning associated val if found
     83 Bool delFromFM ( WordFM* fm, /*OUT*/Word* oldV, Word key );
     84 
     85 // Look up in fm, assigning found val at spec'd address
     86 Bool lookupFM ( WordFM* fm, /*OUT*/Word* valP, Word key );
     87 
     88 Word sizeFM ( WordFM* fm );
     89 
     90 // set up FM for iteration
     91 void initIterFM ( WordFM* fm );
     92 
     93 // get next key/val pair.  Will assert if fm has been modified
     94 // or looked up in since initIterFM was called.
     95 Bool nextIterFM ( WordFM* fm, /*OUT*/Word* pKey, /*OUT*/Word* pVal );
     96 
     97 // clear the I'm iterating flag
     98 void doneIterFM ( WordFM* fm );
     99 
    100 // Deep copy a FM.  If dopyK is NULL, keys are copied verbatim.
    101 // If non-null, dopyK is applied to each key to generate the
    102 // version in the new copy.  In that case, if the argument to dopyK
    103 // is non-NULL but the result is NULL, it is assumed that dopyK
    104 // could not allocate memory, in which case the copy is abandoned
    105 // and NULL is returned.  Ditto with dopyV for values.
    106 WordFM* dopyFM ( WordFM* fm, Word(*dopyK)(Word), Word(*dopyV)(Word) );
    107 
    108 //------------------------------------------------------------------//
    109 //---                         end WordFM                         ---//
    110 //---                      Public interface                      ---//
    111 //------------------------------------------------------------------//
    112 
    113 
    114 static const char* argv0 = "cg_merge";
    115 
    116 /* Keep track of source filename/line no so as to be able to
    117    print decent error messages. */
    118 typedef
    119    struct {
    120       FILE* fp;
    121       UInt  lno;
    122       char* filename;
    123    }
    124    SOURCE;
    125 
    126 static void printSrcLoc ( SOURCE* s )
    127 {
    128    fprintf(stderr, "%s: near %s line %u\n", argv0, s->filename, s->lno-1);
    129 }
    130 
    131 __attribute__((noreturn))
    132 static void mallocFail ( SOURCE* s, const char* who )
    133 {
    134    fprintf(stderr, "%s: out of memory in %s\n", argv0, who );
    135    printSrcLoc( s );
    136    exit(2);
    137 }
    138 
    139 __attribute__((noreturn))
    140 static void parseError ( SOURCE* s, const char* msg )
    141 {
    142    fprintf(stderr, "%s: parse error: %s\n", argv0, msg );
    143    printSrcLoc( s );
    144    exit(1);
    145 }
    146 
    147 __attribute__((noreturn))
    148 static void barf ( SOURCE* s, const char* msg )
    149 {
    150    fprintf(stderr, "%s: %s\n", argv0, msg );
    151    printSrcLoc( s );
    152    exit(1);
    153 }
    154 
    155 // Read a line
    156 #define M_LINEBUF 40960
    157 static char line[M_LINEBUF];
    158 
    159 // True if anything read, False if at EOF
    160 static Bool readline ( SOURCE* s )
    161 {
    162    int ch, i = 0;
    163    line[0] = 0;
    164    while (1) {
    165       if (i >= M_LINEBUF-10)
    166          parseError(s, "Unexpected long line in input file");
    167       ch = getc(s->fp);
    168       if (ch != EOF) {
    169           line[i++] = ch;
    170           line[i] = 0;
    171           if (ch == '\n') {
    172              line[i-1] = 0;
    173              s->lno++;
    174              break;
    175           }
    176       } else {
    177          if (ferror(s->fp)) {
    178             perror(argv0);
    179             barf(s, "I/O error while reading input file");
    180          } else {
    181             // hit EOF
    182             break;
    183          }
    184       }
    185    }
    186    return line[0] != 0;
    187 }
    188 
    189 static Bool streqn ( const char* s1, const char* s2, size_t n )
    190 {
    191    return 0 == strncmp(s1, s2, n);
    192 }
    193 
    194 static Bool streq ( const char* s1, const char* s2 )
    195 {
    196    return 0 == strcmp(s1, s2 );
    197 }
    198 
    199 
    200 ////////////////////////////////////////////////////////////////
    201 
    202 typedef
    203    struct {
    204       char* fi_name;
    205       char* fn_name;
    206    }
    207    FileFn;
    208 
    209 typedef
    210    struct {
    211       Int n_counts;
    212       ULong* counts;
    213    }
    214    Counts;
    215 
    216 typedef
    217    struct {
    218       // null-terminated vector of desc_lines
    219       char** desc_lines;
    220 
    221       // Cmd line
    222       char* cmd_line;
    223 
    224       // Events line
    225       char* events_line;
    226       Int   n_events;
    227 
    228       // Summary line (copied from input)
    229       char* summary_line;
    230 
    231       /* Outermost map is
    232             WordFM FileFn* innerMap
    233          where innerMap is   WordFM line-number=UWord Counts */
    234       WordFM* outerMap;
    235 
    236       // Summary counts (computed whilst parsing)
    237       // should match .summary_line
    238       Counts* summary;
    239    }
    240    CacheProfFile;
    241 
    242 static FileFn* new_FileFn ( char* file_name, char* fn_name )
    243 {
    244    FileFn* ffn = malloc(sizeof(FileFn));
    245    if (ffn == NULL)
    246       return NULL;
    247    ffn->fi_name = file_name;
    248    ffn->fn_name = fn_name;
    249    return ffn;
    250 }
    251 
    252 static void ddel_FileFn ( FileFn* ffn )
    253 {
    254    if (ffn->fi_name)
    255       free(ffn->fi_name);
    256    if (ffn->fn_name)
    257       free(ffn->fn_name);
    258    memset(ffn, 0, sizeof(FileFn));
    259    free(ffn);
    260 }
    261 
    262 static FileFn* dopy_FileFn ( FileFn* ff )
    263 {
    264    char* fi2 = strdup(ff->fi_name);
    265    char* fn2 = strdup(ff->fn_name);
    266    if ((!fi2) || (!fn2))
    267       return NULL;
    268    return new_FileFn( fi2, fn2 );
    269 }
    270 
    271 static Counts* new_Counts ( Int n_counts, /*COPIED*/ULong* counts )
    272 {
    273    Int i;
    274    Counts* cts = malloc(sizeof(Counts));
    275    if (cts == NULL)
    276       return NULL;
    277 
    278    assert(n_counts >= 0);
    279    cts->counts = malloc(n_counts * sizeof(ULong));
    280    if (cts->counts == NULL) {
    281       free(cts);
    282       return NULL;
    283    }
    284 
    285    cts->n_counts = n_counts;
    286    for (i = 0; i < n_counts; i++)
    287       cts->counts[i] = counts[i];
    288 
    289    return cts;
    290 }
    291 
    292 static Counts* new_Counts_Zeroed ( Int n_counts )
    293 {
    294    Int i;
    295    Counts* cts = malloc(sizeof(Counts));
    296    if (cts == NULL)
    297       return NULL;
    298 
    299    assert(n_counts >= 0);
    300    cts->counts = malloc(n_counts * sizeof(ULong));
    301    if (cts->counts == NULL) {
    302       free(cts);
    303       return NULL;
    304    }
    305 
    306    cts->n_counts = n_counts;
    307    for (i = 0; i < n_counts; i++)
    308       cts->counts[i] = 0;
    309 
    310    return cts;
    311 }
    312 
    313 static void sdel_Counts ( Counts* cts )
    314 {
    315    memset(cts, 0, sizeof(Counts));
    316    free(cts);
    317 }
    318 
    319 static void ddel_Counts ( Counts* cts )
    320 {
    321    if (cts->counts)
    322       free(cts->counts);
    323    memset(cts, 0, sizeof(Counts));
    324    free(cts);
    325 }
    326 
    327 static Counts* dopy_Counts ( Counts* cts )
    328 {
    329    return new_Counts( cts->n_counts, cts->counts );
    330 }
    331 
    332 static
    333 CacheProfFile* new_CacheProfFile ( char**  desc_lines,
    334                                    char*   cmd_line,
    335                                    char*   events_line,
    336                                    Int     n_events,
    337                                    char*   summary_line,
    338                                    WordFM* outerMap,
    339                                    Counts* summary )
    340 {
    341    CacheProfFile* cpf = malloc(sizeof(CacheProfFile));
    342    if (cpf == NULL)
    343       return NULL;
    344    cpf->desc_lines   = desc_lines;
    345    cpf->cmd_line     = cmd_line;
    346    cpf->events_line  = events_line;
    347    cpf->n_events     = n_events;
    348    cpf->summary_line = summary_line;
    349    cpf->outerMap     = outerMap;
    350    cpf->summary      = summary;
    351    return cpf;
    352 }
    353 
    354 static WordFM* dopy_InnerMap ( WordFM* innerMap )
    355 {
    356    return dopyFM ( innerMap, NULL,
    357                              (Word(*)(Word))dopy_Counts );
    358 }
    359 
    360 static void ddel_InnerMap ( WordFM* innerMap )
    361 {
    362    deleteFM( innerMap, NULL, (void(*)(Word))ddel_Counts );
    363 }
    364 
    365 static void ddel_CacheProfFile ( CacheProfFile* cpf )
    366 {
    367    char** p;
    368    if (cpf->desc_lines) {
    369       for (p = cpf->desc_lines; *p; p++)
    370          free(*p);
    371       free(cpf->desc_lines);
    372    }
    373    if (cpf->cmd_line)
    374       free(cpf->cmd_line);
    375    if (cpf->events_line)
    376       free(cpf->events_line);
    377    if (cpf->summary_line)
    378       free(cpf->summary_line);
    379    if (cpf->outerMap)
    380       deleteFM( cpf->outerMap, (void(*)(Word))ddel_FileFn,
    381                                (void(*)(Word))ddel_InnerMap );
    382    if (cpf->summary)
    383       ddel_Counts(cpf->summary);
    384 
    385    memset(cpf, 0, sizeof(CacheProfFile));
    386    free(cpf);
    387 }
    388 
    389 static void showCounts ( FILE* f, Counts* c )
    390 {
    391    Int i;
    392    for (i = 0; i < c->n_counts; i++) {
    393       fprintf(f, "%lld ", c->counts[i]);
    394    }
    395 }
    396 
    397 static void show_CacheProfFile ( FILE* f, CacheProfFile* cpf )
    398 {
    399    Int     i;
    400    char**  d;
    401    FileFn* topKey;
    402    WordFM* topVal;
    403    UWord   subKey;
    404    Counts* subVal;
    405 
    406    for (d = cpf->desc_lines; *d; d++)
    407       fprintf(f, "%s\n", *d);
    408    fprintf(f, "%s\n", cpf->cmd_line);
    409    fprintf(f, "%s\n", cpf->events_line);
    410 
    411    initIterFM( cpf->outerMap );
    412    while (nextIterFM( cpf->outerMap, (Word*)(&topKey), (Word*)(&topVal) )) {
    413       fprintf(f, "fl=%s\nfn=%s\n",
    414                  topKey->fi_name, topKey->fn_name );
    415       initIterFM( topVal );
    416       while (nextIterFM( topVal, (Word*)(&subKey), (Word*)(&subVal) )) {
    417          fprintf(f, "%ld   ", subKey );
    418          showCounts( f, subVal );
    419          fprintf(f, "\n");
    420       }
    421       doneIterFM( topVal );
    422    }
    423    doneIterFM( cpf->outerMap );
    424 
    425    //fprintf(f, "%s\n", cpf->summary_line);
    426    fprintf(f, "summary:");
    427    for (i = 0; i < cpf->summary->n_counts; i++)
    428       fprintf(f, " %lld", cpf->summary->counts[i]);
    429    fprintf(f, "\n");
    430 }
    431 
    432 ////////////////////////////////////////////////////////////////
    433 
    434 static Word cmp_FileFn ( Word s1, Word s2 )
    435 {
    436    FileFn* ff1 = (FileFn*)s1;
    437    FileFn* ff2 = (FileFn*)s2;
    438    Word r = strcmp(ff1->fi_name, ff2->fi_name);
    439    if (r == 0)
    440       r = strcmp(ff1->fn_name, ff2->fn_name);
    441    return r;
    442 }
    443 
    444 static Word cmp_unboxed_UWord ( Word s1, Word s2 )
    445 {
    446    UWord u1 = (UWord)s1;
    447    UWord u2 = (UWord)s2;
    448    if (u1 < u2) return -1;
    449    if (u1 > u2) return 1;
    450    return 0;
    451 }
    452 
    453 ////////////////////////////////////////////////////////////////
    454 
    455 static Bool parse_ULong ( /*OUT*/ULong* res, /*INOUT*/char** pptr)
    456 {
    457    ULong u64;
    458    char* ptr = *pptr;
    459    while (isspace(*ptr)) ptr++;
    460    if (!isdigit(*ptr)) {
    461       *pptr = ptr;
    462       return False; /* end of string, or junk */
    463    }
    464    u64 = 0;
    465    while (isdigit(*ptr)) {
    466       u64 = (u64 * 10) + (ULong)(*ptr - '0');
    467       ptr++;
    468    }
    469    *res = u64;
    470    *pptr = ptr;
    471    return True;
    472 }
    473 
    474 // str is a line of digits, starting with a line number.  Parse it,
    475 // returning the first number in *lnno and the rest in a newly
    476 // allocated Counts struct.  If lnno is non-NULL, treat the first
    477 // number as a line number and assign it to *lnno instead of
    478 // incorporating it in the counts array.
    479 static
    480 Counts* splitUpCountsLine ( SOURCE* s, /*OUT*/UWord* lnno, char* str )
    481 {
    482 #define N_TMPC 50
    483    Bool    ok;
    484    Counts* counts;
    485    ULong   tmpC[N_TMPC];
    486    Int     n_tmpC = 0;
    487    while (1) {
    488       ok = parse_ULong( &tmpC[n_tmpC], &str );
    489       if (!ok)
    490          break;
    491       n_tmpC++;
    492       if (n_tmpC >= N_TMPC)
    493          barf(s, "N_TMPC too low.  Increase and recompile.");
    494    }
    495    if (*str != 0)
    496       parseError(s, "garbage in counts line");
    497    if (lnno ? (n_tmpC < 2) : (n_tmpC < 1))
    498       parseError(s, "too few counts in count line");
    499 
    500    if (lnno) {
    501       *lnno = (UWord)tmpC[0];
    502       counts = new_Counts( n_tmpC-1, /*COPIED*/&tmpC[1] );
    503    } else {
    504       counts = new_Counts( n_tmpC, /*COPIED*/&tmpC[0] );
    505    }
    506 
    507    return counts;
    508 #undef N_TMPC
    509 }
    510 
    511 static void addCounts ( SOURCE* s, /*OUT*/Counts* counts1, Counts* counts2 )
    512 {
    513    Int i;
    514    if (counts1->n_counts != counts2->n_counts)
    515       parseError(s, "addCounts: inconsistent number of counts");
    516    for (i = 0; i < counts1->n_counts; i++)
    517       counts1->counts[i] += counts2->counts[i];
    518 }
    519 
    520 static Bool addCountsToMap ( SOURCE* s,
    521                              WordFM* counts_map,
    522                              UWord lnno, Counts* newCounts )
    523 {
    524    Counts* oldCounts;
    525    // look up lnno in the map.  If none present, add a binding
    526    // lnno->counts.  If present, add counts to the existing entry.
    527    if (lookupFM( counts_map, (Word*)(&oldCounts), (Word)lnno )) {
    528       // merge with existing binding
    529       addCounts( s, oldCounts, newCounts );
    530       return True;
    531    } else {
    532       // create new binding
    533       addToFM( counts_map, (Word)lnno, (Word)newCounts );
    534       return False;
    535    }
    536 }
    537 
    538 static
    539 void handle_counts ( SOURCE* s,
    540                      CacheProfFile* cpf,
    541                      const char* fi, const char* fn, char* newCountsStr )
    542 {
    543    WordFM* countsMap;
    544    Bool    freeNewCounts;
    545    UWord   lnno;
    546    Counts* newCounts;
    547    FileFn* topKey;
    548 
    549    if (0)  printf("%s %s %s\n", fi, fn, newCountsStr );
    550 
    551    // parse the numbers
    552    newCounts = splitUpCountsLine( s, &lnno, newCountsStr );
    553 
    554    // Did we get the right number?
    555    if (newCounts->n_counts != cpf->n_events)
    556       goto oom;
    557 
    558    // allocate the key
    559    topKey = malloc(sizeof(FileFn));
    560    if (topKey) {
    561       topKey->fi_name = strdup(fi);
    562       topKey->fn_name = strdup(fn);
    563    }
    564    if (! (topKey && topKey->fi_name && topKey->fn_name))
    565       mallocFail(s, "handle_counts:");
    566 
    567    // search for it
    568    if (lookupFM( cpf->outerMap, (Word*)(&countsMap), (Word)topKey )) {
    569       // found it.  Merge in new counts
    570       freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts );
    571       ddel_FileFn(topKey);
    572    } else {
    573       // not found in the top map.  Create new entry
    574       countsMap = newFM( malloc, free, cmp_unboxed_UWord );
    575       if (!countsMap)
    576          goto oom;
    577       addToFM( cpf->outerMap, (Word)topKey, (Word)countsMap );
    578       freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts );
    579    }
    580 
    581    // also add to running summary total
    582    addCounts( s, cpf->summary, newCounts );
    583 
    584    // if safe to do so, free up the count vector
    585    if (freeNewCounts)
    586       ddel_Counts(newCounts);
    587 
    588    return;
    589 
    590   oom:
    591    parseError(s, "# counts doesn't match # events");
    592 }
    593 
    594 
    595 /* Parse a complete file from the stream in 's'.  If a parse error
    596    happens, do not return; instead exit via parseError().  If an
    597    out-of-memory condition happens, do not return; instead exit via
    598    mallocError().
    599 */
    600 static CacheProfFile* parse_CacheProfFile ( SOURCE* s )
    601 {
    602 #define M_TMP_DESCLINES 10
    603 
    604    Int            i;
    605    Bool           b;
    606    char*          tmp_desclines[M_TMP_DESCLINES];
    607    char*          p;
    608    int            n_tmp_desclines = 0;
    609    CacheProfFile* cpf;
    610    Counts*        summaryRead;
    611    char*          curr_fn = strdup("???");
    612    char*          curr_fl = strdup("???");
    613 
    614    cpf = new_CacheProfFile( NULL, NULL, NULL, 0, NULL, NULL, NULL );
    615    if (cpf == NULL)
    616       mallocFail(s, "parse_CacheProfFile(1)");
    617 
    618    // Parse "desc:" lines
    619    while (1) {
    620       b = readline(s);
    621       if (!b)
    622          break;
    623       if (!streqn(line, "desc: ", 6))
    624          break;
    625       if (n_tmp_desclines >= M_TMP_DESCLINES)
    626          barf(s, "M_TMP_DESCLINES too low; increase and recompile");
    627       tmp_desclines[n_tmp_desclines++] = strdup(line);
    628    }
    629 
    630    if (n_tmp_desclines == 0)
    631       parseError(s, "parse_CacheProfFile: no DESC lines present");
    632 
    633    cpf->desc_lines = malloc( (1+n_tmp_desclines) * sizeof(char*) );
    634    if (cpf->desc_lines == NULL)
    635       mallocFail(s, "parse_CacheProfFile(2)");
    636 
    637    cpf->desc_lines[n_tmp_desclines] = NULL;
    638    for (i = 0; i < n_tmp_desclines; i++)
    639       cpf->desc_lines[i] = tmp_desclines[i];
    640 
    641    // Parse "cmd:" line
    642    if (!streqn(line, "cmd: ", 5))
    643       parseError(s, "parse_CacheProfFile: no CMD line present");
    644 
    645    cpf->cmd_line = strdup(line);
    646    if (cpf->cmd_line == NULL)
    647       mallocFail(s, "parse_CacheProfFile(3)");
    648 
    649    // Parse "events:" line and figure out how many events there are
    650    b = readline(s);
    651    if (!b)
    652       parseError(s, "parse_CacheProfFile: eof before EVENTS line");
    653    if (!streqn(line, "events: ", 8))
    654       parseError(s, "parse_CacheProfFile: no EVENTS line present");
    655 
    656    // figure out how many events there are by counting the number
    657    // of space-alphanum transitions in the events_line
    658    cpf->events_line = strdup(line);
    659    if (cpf->events_line == NULL)
    660       mallocFail(s, "parse_CacheProfFile(3)");
    661 
    662    cpf->n_events = 0;
    663    assert(cpf->events_line[6] == ':');
    664    for (p = &cpf->events_line[6]; *p; p++) {
    665       if (p[0] == ' ' && isalpha(p[1]))
    666          cpf->n_events++;
    667    }
    668 
    669    // create the running cross-check summary
    670    cpf->summary = new_Counts_Zeroed( cpf->n_events );
    671    if (cpf->summary == NULL)
    672       mallocFail(s, "parse_CacheProfFile(4)");
    673 
    674    // create the outer map (file+fn name --> inner map)
    675    cpf->outerMap = newFM ( malloc, free, cmp_FileFn );
    676    if (cpf->outerMap == NULL)
    677       mallocFail(s, "parse_CacheProfFile(5)");
    678 
    679    // process count lines
    680    while (1) {
    681       b = readline(s);
    682       if (!b)
    683          parseError(s, "parse_CacheProfFile: eof before SUMMARY line");
    684 
    685       if (isdigit(line[0])) {
    686          handle_counts(s, cpf, curr_fl, curr_fn, line);
    687          continue;
    688       }
    689       else
    690       if (streqn(line, "fn=", 3)) {
    691          free(curr_fn);
    692          curr_fn = strdup(line+3);
    693          continue;
    694       }
    695       else
    696       if (streqn(line, "fl=", 3)) {
    697          free(curr_fl);
    698          curr_fl = strdup(line+3);
    699          continue;
    700       }
    701       else
    702       if (streqn(line, "summary: ", 9)) {
    703          break;
    704       }
    705       else
    706          parseError(s, "parse_CacheProfFile: unexpected line in main data");
    707    }
    708 
    709    // finally, the "summary:" line
    710    if (!streqn(line, "summary: ", 9))
    711       parseError(s, "parse_CacheProfFile: missing SUMMARY line");
    712 
    713    cpf->summary_line = strdup(line);
    714    if (cpf->summary_line == NULL)
    715       mallocFail(s, "parse_CacheProfFile(6)");
    716 
    717    // there should be nothing more
    718    b = readline(s);
    719    if (b)
    720       parseError(s, "parse_CacheProfFile: "
    721                     "extraneous content after SUMMARY line");
    722 
    723    // check the summary counts are as expected
    724    summaryRead = splitUpCountsLine( s, NULL, &cpf->summary_line[8] );
    725    if (summaryRead == NULL)
    726       mallocFail(s, "parse_CacheProfFile(7)");
    727    if (summaryRead->n_counts != cpf->n_events)
    728       parseError(s, "parse_CacheProfFile: wrong # counts in SUMMARY line");
    729    for (i = 0; i < summaryRead->n_counts; i++) {
    730       if (summaryRead->counts[i] != cpf->summary->counts[i]) {
    731          parseError(s, "parse_CacheProfFile: "
    732                        "computed vs stated SUMMARY counts mismatch");
    733       }
    734    }
    735    free(summaryRead->counts);
    736    sdel_Counts(summaryRead);
    737 
    738    // since the summary counts are OK, free up the summary_line text
    739    // which contains the same info.
    740    if (cpf->summary_line) {
    741       free(cpf->summary_line);
    742       cpf->summary_line = NULL;
    743    }
    744 
    745    free(curr_fn);
    746    free(curr_fl);
    747 
    748    // All looks OK
    749    return cpf;
    750 
    751 #undef N_TMP_DESCLINES
    752 }
    753 
    754 
    755 static void merge_CacheProfInfo ( SOURCE* s,
    756                                   /*MOD*/CacheProfFile* dst,
    757                                   CacheProfFile* src )
    758 {
    759    /* For each (filefn, innerMap) in src
    760       if filefn not in dst
    761          add binding dopy(filefn)->dopy(innerMap) in src
    762       else
    763          // merge src->innerMap with dst->innerMap
    764          for each (lineno, counts) in src->innerMap
    765          if lineno not in dst->innerMap
    766             add binding lineno->dopy(counts) to dst->innerMap
    767          else
    768             add counts into dst->innerMap[lineno]
    769    */
    770    /* Outer iterator:  FileFn* -> WordFM* (inner iterator)
    771       Inner iterator:  UWord   -> Counts*
    772    */
    773    FileFn* soKey;
    774    WordFM* soVal;
    775    WordFM* doVal;
    776    UWord   siKey;
    777    Counts* siVal;
    778    Counts* diVal;
    779 
    780    /* First check mundane things: that the events: lines are
    781       identical. */
    782    if (!streq( dst->events_line, src->events_line ))
    783      barf(s, "\"events:\" line of most recent file does "
    784              "not match those previously processed");
    785 
    786    initIterFM( src->outerMap );
    787 
    788    // for (filefn, innerMap) in src
    789    while (nextIterFM( src->outerMap, (Word*)&soKey, (Word*)&soVal )) {
    790 
    791       // is filefn in dst?
    792       if (! lookupFM( dst->outerMap, (Word*)&doVal, (Word)soKey )) {
    793 
    794          // no .. add dopy(filefn) -> dopy(innerMap) to src
    795          FileFn* c_soKey = dopy_FileFn(soKey);
    796          WordFM* c_soVal = dopy_InnerMap(soVal);
    797          if ((!c_soKey) || (!c_soVal)) goto oom;
    798          addToFM( dst->outerMap, (Word)c_soKey, (Word)c_soVal );
    799 
    800       } else {
    801 
    802          // yes .. merge the two innermaps
    803          initIterFM( soVal );
    804 
    805          // for (lno, counts) in soVal (source inner map)
    806          while (nextIterFM( soVal, (Word*)&siKey, (Word*)&siVal )) {
    807 
    808             // is lno in the corresponding dst inner map?
    809             if (! lookupFM( doVal, (Word*)&diVal, siKey )) {
    810 
    811                // no .. add lineno->dopy(counts) to dst inner map
    812                Counts* c_siVal = dopy_Counts( siVal );
    813                if (!c_siVal) goto oom;
    814                addToFM( doVal, siKey, (Word)c_siVal );
    815 
    816             } else {
    817 
    818                // yes .. merge counts into dst inner map val
    819                addCounts( s, diVal, siVal );
    820 
    821             }
    822          }
    823 
    824       }
    825 
    826    }
    827 
    828    // add the summaries too
    829    addCounts(s, dst->summary, src->summary );
    830 
    831    return;
    832 
    833   oom:
    834    mallocFail(s, "merge_CacheProfInfo");
    835 }
    836 
    837 static void usage ( void )
    838 {
    839    fprintf(stderr, "%s: Merges multiple cachegrind output files into one\n",
    840                    argv0);
    841    fprintf(stderr, "%s: usage: %s [-o outfile] [files-to-merge]\n",
    842                    argv0, argv0);
    843    exit(1);
    844 }
    845 
    846 int main ( int argc, char** argv )
    847 {
    848    Int            i;
    849    SOURCE         src;
    850    CacheProfFile  *cpf, *cpfTmp;
    851 
    852    FILE*          outfile = NULL;
    853    char*          outfilename = NULL;
    854    Int            outfileix = 0;
    855 
    856    if (argv[0])
    857       argv0 = argv[0];
    858 
    859    if (argc < 2)
    860       usage();
    861 
    862    for (i = 1; i < argc; i++) {
    863       if (streq(argv[i], "-h") || streq(argv[i], "--help"))
    864          usage();
    865    }
    866 
    867    /* Scan args, looking for '-o outfilename'. */
    868    for (i = 1; i < argc; i++) {
    869       if (streq(argv[i], "-o")) {
    870          if (i+1 < argc) {
    871             outfilename = argv[i+1];
    872             outfileix   = i;
    873             break;
    874          } else {
    875             usage();
    876          }
    877       }
    878    }
    879 
    880    cpf = NULL;
    881 
    882    for (i = 1; i < argc; i++) {
    883 
    884       if (i == outfileix) {
    885          /* Skip '-o' and whatever follows it */
    886          i += 1;
    887          continue;
    888       }
    889 
    890       fprintf(stderr, "%s: parsing %s\n", argv0, argv[i]);
    891       src.lno      = 1;
    892       src.filename = argv[i];
    893       src.fp       = fopen(src.filename, "r");
    894       if (!src.fp) {
    895          perror(argv0);
    896          barf(&src, "Cannot open input file");
    897       }
    898       assert(src.fp);
    899       cpfTmp = parse_CacheProfFile( &src );
    900       fclose(src.fp);
    901 
    902       /* If this isn't the first file, merge */
    903       if (cpf == NULL) {
    904          /* this is the first file */
    905          cpf = cpfTmp;
    906       } else {
    907          /* not the first file; merge */
    908          fprintf(stderr, "%s: merging %s\n", argv0, argv[i]);
    909          merge_CacheProfInfo( &src, cpf, cpfTmp );
    910          ddel_CacheProfFile( cpfTmp );
    911       }
    912 
    913    }
    914 
    915    /* Now create the output file. */
    916 
    917    if (cpf) {
    918 
    919       fprintf(stderr, "%s: writing %s\n",
    920                        argv0, outfilename ? outfilename : "(stdout)" );
    921 
    922       /* Write the output. */
    923       if (outfilename) {
    924          outfile = fopen(outfilename, "w");
    925          if (!outfile) {
    926             fprintf(stderr, "%s: can't create output file %s\n",
    927                             argv0, outfilename);
    928             perror(argv0);
    929             exit(1);
    930          }
    931       } else {
    932          outfile = stdout;
    933       }
    934 
    935       show_CacheProfFile( outfile, cpf );
    936       if (ferror(outfile)) {
    937          fprintf(stderr, "%s: error writing output file %s\n",
    938                          argv0, outfilename ? outfilename : "(stdout)" );
    939          perror(argv0);
    940          if (outfile != stdout)
    941             fclose(outfile);
    942          exit(1);
    943       }
    944 
    945       fflush(outfile);
    946       if (outfile != stdout)
    947          fclose( outfile );
    948 
    949       ddel_CacheProfFile( cpf );
    950    }
    951 
    952    return 0;
    953 }
    954 
    955 
    956 //------------------------------------------------------------------//
    957 //---                           WordFM                           ---//
    958 //---                       Implementation                       ---//
    959 //------------------------------------------------------------------//
    960 
    961 /* ------------ Implementation ------------ */
    962 
    963 /* One element of the AVL tree */
    964 typedef
    965    struct _AvlNode {
    966       Word key;
    967       Word val;
    968       struct _AvlNode* left;
    969       struct _AvlNode* right;
    970       Char balance;
    971    }
    972    AvlNode;
    973 
    974 typedef
    975    struct {
    976       Word w;
    977       Bool b;
    978    }
    979    MaybeWord;
    980 
    981 #define WFM_STKMAX    32    // At most 2**32 entries can be iterated over
    982 
    983 struct _WordFM {
    984    AvlNode* root;
    985    void*    (*alloc_nofail)( SizeT );
    986    void     (*dealloc)(void*);
    987    Word     (*kCmp)(Word,Word);
    988    AvlNode* nodeStack[WFM_STKMAX]; // Iterator node stack
    989    Int      numStack[WFM_STKMAX];  // Iterator num stack
    990    Int      stackTop;              // Iterator stack pointer, one past end
    991 };
    992 
    993 /* forward */
    994 static Bool avl_removeroot_wrk(AvlNode** t, Word(*kCmp)(Word,Word));
    995 
    996 /* Swing to the left.  Warning: no balance maintainance. */
    997 static void avl_swl ( AvlNode** root )
    998 {
    999    AvlNode* a = *root;
   1000    AvlNode* b = a->right;
   1001    *root    = b;
   1002    a->right = b->left;
   1003    b->left  = a;
   1004 }
   1005 
   1006 /* Swing to the right.  Warning: no balance maintainance. */
   1007 static void avl_swr ( AvlNode** root )
   1008 {
   1009    AvlNode* a = *root;
   1010    AvlNode* b = a->left;
   1011    *root    = b;
   1012    a->left  = b->right;
   1013    b->right = a;
   1014 }
   1015 
   1016 /* Balance maintainance after especially nasty swings. */
   1017 static void avl_nasty ( AvlNode* root )
   1018 {
   1019    switch (root->balance) {
   1020       case -1:
   1021          root->left->balance  = 0;
   1022          root->right->balance = 1;
   1023          break;
   1024       case 1:
   1025          root->left->balance  = -1;
   1026          root->right->balance = 0;
   1027          break;
   1028       case 0:
   1029          root->left->balance  = 0;
   1030          root->right->balance = 0;
   1031          break;
   1032       default:
   1033          assert(0);
   1034    }
   1035    root->balance=0;
   1036 }
   1037 
   1038 /* Find size of a non-NULL tree. */
   1039 static Word size_avl_nonNull ( AvlNode* nd )
   1040 {
   1041    return 1 + (nd->left  ? size_avl_nonNull(nd->left)  : 0)
   1042             + (nd->right ? size_avl_nonNull(nd->right) : 0);
   1043 }
   1044 
   1045 /* Insert element a into the AVL tree t.  Returns True if the depth of
   1046    the tree has grown.  If element with that key is already present,
   1047    just copy a->val to existing node, first returning old ->val field
   1048    of existing node in *oldV, so that the caller can finalize it
   1049    however it wants.
   1050 */
   1051 static
   1052 Bool avl_insert_wrk ( AvlNode**         rootp,
   1053                       /*OUT*/MaybeWord* oldV,
   1054                       AvlNode*          a,
   1055                       Word              (*kCmp)(Word,Word) )
   1056 {
   1057    Word cmpres;
   1058 
   1059    /* initialize */
   1060    a->left    = 0;
   1061    a->right   = 0;
   1062    a->balance = 0;
   1063    oldV->b    = False;
   1064 
   1065    /* insert into an empty tree? */
   1066    if (!(*rootp)) {
   1067       (*rootp) = a;
   1068       return True;
   1069    }
   1070 
   1071    cmpres = kCmp( (*rootp)->key, a->key );
   1072 
   1073    if (cmpres > 0) {
   1074       /* insert into the left subtree */
   1075       if ((*rootp)->left) {
   1076          AvlNode* left_subtree = (*rootp)->left;
   1077          if (avl_insert_wrk(&left_subtree, oldV, a, kCmp)) {
   1078             switch ((*rootp)->balance--) {
   1079                case  1: return False;
   1080                case  0: return True;
   1081                case -1: break;
   1082                default: assert(0);
   1083             }
   1084             if ((*rootp)->left->balance < 0) {
   1085                avl_swr( rootp );
   1086                (*rootp)->balance = 0;
   1087                (*rootp)->right->balance = 0;
   1088             } else {
   1089                avl_swl( &((*rootp)->left) );
   1090                avl_swr( rootp );
   1091                avl_nasty( *rootp );
   1092             }
   1093          } else {
   1094             (*rootp)->left = left_subtree;
   1095          }
   1096          return False;
   1097       } else {
   1098          (*rootp)->left = a;
   1099          if ((*rootp)->balance--)
   1100             return False;
   1101          return True;
   1102       }
   1103       assert(0);/*NOTREACHED*/
   1104    }
   1105    else
   1106    if (cmpres < 0) {
   1107       /* insert into the right subtree */
   1108       if ((*rootp)->right) {
   1109          AvlNode* right_subtree = (*rootp)->right;
   1110          if (avl_insert_wrk(&right_subtree, oldV, a, kCmp)) {
   1111             switch((*rootp)->balance++){
   1112                case -1: return False;
   1113                case  0: return True;
   1114                case  1: break;
   1115                default: assert(0);
   1116             }
   1117             if ((*rootp)->right->balance > 0) {
   1118                avl_swl( rootp );
   1119                (*rootp)->balance = 0;
   1120                (*rootp)->left->balance = 0;
   1121             } else {
   1122                avl_swr( &((*rootp)->right) );
   1123                avl_swl( rootp );
   1124                avl_nasty( *rootp );
   1125             }
   1126          } else {
   1127             (*rootp)->right = right_subtree;
   1128          }
   1129          return False;
   1130       } else {
   1131          (*rootp)->right = a;
   1132          if ((*rootp)->balance++)
   1133             return False;
   1134          return True;
   1135       }
   1136       assert(0);/*NOTREACHED*/
   1137    }
   1138    else {
   1139       /* cmpres == 0, a duplicate - replace the val, but don't
   1140          incorporate the node in the tree */
   1141       oldV->b = True;
   1142       oldV->w = (*rootp)->val;
   1143       (*rootp)->val = a->val;
   1144       return False;
   1145    }
   1146 }
   1147 
   1148 /* Remove an element a from the AVL tree t.  a must be part of
   1149    the tree.  Returns True if the depth of the tree has shrunk.
   1150 */
   1151 static
   1152 Bool avl_remove_wrk ( AvlNode** rootp,
   1153                       AvlNode*  a,
   1154                       Word(*kCmp)(Word,Word) )
   1155 {
   1156    Bool ch;
   1157    Word cmpres = kCmp( (*rootp)->key, a->key );
   1158 
   1159    if (cmpres > 0){
   1160       /* remove from the left subtree */
   1161       AvlNode* left_subtree = (*rootp)->left;
   1162       assert(left_subtree);
   1163       ch = avl_remove_wrk(&left_subtree, a, kCmp);
   1164       (*rootp)->left=left_subtree;
   1165       if (ch) {
   1166          switch ((*rootp)->balance++) {
   1167             case -1: return True;
   1168             case  0: return False;
   1169             case  1: break;
   1170             default: assert(0);
   1171          }
   1172          switch ((*rootp)->right->balance) {
   1173             case 0:
   1174                avl_swl( rootp );
   1175                (*rootp)->balance = -1;
   1176                (*rootp)->left->balance = 1;
   1177                return False;
   1178             case 1:
   1179                avl_swl( rootp );
   1180                (*rootp)->balance = 0;
   1181                (*rootp)->left->balance = 0;
   1182                return -1;
   1183             case -1:
   1184                break;
   1185             default:
   1186                assert(0);
   1187          }
   1188          avl_swr( &((*rootp)->right) );
   1189          avl_swl( rootp );
   1190          avl_nasty( *rootp );
   1191          return True;
   1192       }
   1193    }
   1194    else
   1195    if (cmpres < 0) {
   1196       /* remove from the right subtree */
   1197       AvlNode* right_subtree = (*rootp)->right;
   1198       assert(right_subtree);
   1199       ch = avl_remove_wrk(&right_subtree, a, kCmp);
   1200       (*rootp)->right = right_subtree;
   1201       if (ch) {
   1202          switch ((*rootp)->balance--) {
   1203             case  1: return True;
   1204             case  0: return False;
   1205             case -1: break;
   1206             default: assert(0);
   1207          }
   1208          switch ((*rootp)->left->balance) {
   1209             case 0:
   1210                avl_swr( rootp );
   1211                (*rootp)->balance = 1;
   1212                (*rootp)->right->balance = -1;
   1213                return False;
   1214             case -1:
   1215                avl_swr( rootp );
   1216                (*rootp)->balance = 0;
   1217                (*rootp)->right->balance = 0;
   1218                return True;
   1219             case 1:
   1220                break;
   1221             default:
   1222                assert(0);
   1223          }
   1224          avl_swl( &((*rootp)->left) );
   1225          avl_swr( rootp );
   1226          avl_nasty( *rootp );
   1227          return True;
   1228       }
   1229    }
   1230    else {
   1231       assert(cmpres == 0);
   1232       assert((*rootp)==a);
   1233       return avl_removeroot_wrk(rootp, kCmp);
   1234    }
   1235    return 0;
   1236 }
   1237 
   1238 /* Remove the root of the AVL tree *rootp.
   1239  * Warning: dumps core if *rootp is empty
   1240  */
   1241 static
   1242 Bool avl_removeroot_wrk ( AvlNode** rootp,
   1243                           Word(*kCmp)(Word,Word) )
   1244 {
   1245    Bool     ch;
   1246    AvlNode* a;
   1247    if (!(*rootp)->left) {
   1248       if (!(*rootp)->right) {
   1249          (*rootp) = 0;
   1250          return True;
   1251       }
   1252       (*rootp) = (*rootp)->right;
   1253       return True;
   1254    }
   1255    if (!(*rootp)->right) {
   1256       (*rootp) = (*rootp)->left;
   1257       return True;
   1258    }
   1259    if ((*rootp)->balance < 0) {
   1260       /* remove from the left subtree */
   1261       a = (*rootp)->left;
   1262       while (a->right) a = a->right;
   1263    } else {
   1264       /* remove from the right subtree */
   1265       a = (*rootp)->right;
   1266       while (a->left) a = a->left;
   1267    }
   1268    ch = avl_remove_wrk(rootp, a, kCmp);
   1269    a->left    = (*rootp)->left;
   1270    a->right   = (*rootp)->right;
   1271    a->balance = (*rootp)->balance;
   1272    (*rootp)   = a;
   1273    if(a->balance == 0) return ch;
   1274    return False;
   1275 }
   1276 
   1277 static
   1278 AvlNode* avl_find_node ( AvlNode* t, Word k, Word(*kCmp)(Word,Word) )
   1279 {
   1280    Word cmpres;
   1281    while (True) {
   1282       if (t == NULL) return NULL;
   1283       cmpres = kCmp(t->key, k);
   1284       if (cmpres > 0) t = t->left;  else
   1285       if (cmpres < 0) t = t->right; else
   1286       return t;
   1287    }
   1288 }
   1289 
   1290 // Clear the iterator stack.
   1291 static void stackClear(WordFM* fm)
   1292 {
   1293    Int i;
   1294    assert(fm);
   1295    for (i = 0; i < WFM_STKMAX; i++) {
   1296       fm->nodeStack[i] = NULL;
   1297       fm->numStack[i]  = 0;
   1298    }
   1299    fm->stackTop = 0;
   1300 }
   1301 
   1302 // Push onto the iterator stack.
   1303 static inline void stackPush(WordFM* fm, AvlNode* n, Int i)
   1304 {
   1305    assert(fm->stackTop < WFM_STKMAX);
   1306    assert(1 <= i && i <= 3);
   1307    fm->nodeStack[fm->stackTop] = n;
   1308    fm-> numStack[fm->stackTop] = i;
   1309    fm->stackTop++;
   1310 }
   1311 
   1312 // Pop from the iterator stack.
   1313 static inline Bool stackPop(WordFM* fm, AvlNode** n, Int* i)
   1314 {
   1315    assert(fm->stackTop <= WFM_STKMAX);
   1316 
   1317    if (fm->stackTop > 0) {
   1318       fm->stackTop--;
   1319       *n = fm->nodeStack[fm->stackTop];
   1320       *i = fm-> numStack[fm->stackTop];
   1321       assert(1 <= *i && *i <= 3);
   1322       fm->nodeStack[fm->stackTop] = NULL;
   1323       fm-> numStack[fm->stackTop] = 0;
   1324       return True;
   1325    } else {
   1326       return False;
   1327    }
   1328 }
   1329 
   1330 static
   1331 AvlNode* avl_dopy ( AvlNode* nd,
   1332                     Word(*dopyK)(Word),
   1333                     Word(*dopyV)(Word),
   1334                     void*(alloc_nofail)(SizeT) )
   1335 {
   1336    AvlNode* nyu;
   1337    if (! nd)
   1338       return NULL;
   1339    nyu = alloc_nofail(sizeof(AvlNode));
   1340    assert(nyu);
   1341 
   1342    nyu->left = nd->left;
   1343    nyu->right = nd->right;
   1344    nyu->balance = nd->balance;
   1345 
   1346    /* Copy key */
   1347    if (dopyK) {
   1348       nyu->key = dopyK( nd->key );
   1349       if (nd->key != 0 && nyu->key == 0)
   1350          return NULL; /* oom in key dcopy */
   1351    } else {
   1352       /* copying assumedly unboxed keys */
   1353       nyu->key = nd->key;
   1354    }
   1355 
   1356    /* Copy val */
   1357    if (dopyV) {
   1358       nyu->val = dopyV( nd->val );
   1359       if (nd->val != 0 && nyu->val == 0)
   1360          return NULL; /* oom in val dcopy */
   1361    } else {
   1362       /* copying assumedly unboxed vals */
   1363       nyu->val = nd->val;
   1364    }
   1365 
   1366    /* Copy subtrees */
   1367    if (nyu->left) {
   1368       nyu->left = avl_dopy( nyu->left, dopyK, dopyV, alloc_nofail );
   1369       if (! nyu->left)
   1370          return NULL;
   1371    }
   1372    if (nyu->right) {
   1373       nyu->right = avl_dopy( nyu->right, dopyK, dopyV, alloc_nofail );
   1374       if (! nyu->right)
   1375          return NULL;
   1376    }
   1377 
   1378    return nyu;
   1379 }
   1380 
   1381 /* --- Public interface functions --- */
   1382 
   1383 /* Initialise a WordFM. */
   1384 void initFM ( WordFM* fm,
   1385               void*   (*alloc_nofail)( SizeT ),
   1386               void    (*dealloc)(void*),
   1387               Word    (*kCmp)(Word,Word) )
   1388 {
   1389    fm->root         = 0;
   1390    fm->kCmp         = kCmp;
   1391    fm->alloc_nofail = alloc_nofail;
   1392    fm->dealloc      = dealloc;
   1393    fm->stackTop     = 0;
   1394 }
   1395 
   1396 /* Allocate and Initialise a WordFM. */
   1397 WordFM* newFM( void* (*alloc_nofail)( SizeT ),
   1398                void  (*dealloc)(void*),
   1399                Word  (*kCmp)(Word,Word) )
   1400 {
   1401    WordFM* fm = alloc_nofail(sizeof(WordFM));
   1402    assert(fm);
   1403    initFM(fm, alloc_nofail, dealloc, kCmp);
   1404    return fm;
   1405 }
   1406 
   1407 static void avl_free ( AvlNode* nd,
   1408                        void(*kFin)(Word),
   1409                        void(*vFin)(Word),
   1410                        void(*dealloc)(void*) )
   1411 {
   1412    if (!nd)
   1413       return;
   1414    if (nd->left)
   1415       avl_free(nd->left, kFin, vFin, dealloc);
   1416    if (nd->right)
   1417       avl_free(nd->right, kFin, vFin, dealloc);
   1418    if (kFin)
   1419       kFin( nd->key );
   1420    if (vFin)
   1421       vFin( nd->val );
   1422    memset(nd, 0, sizeof(AvlNode));
   1423    dealloc(nd);
   1424 }
   1425 
   1426 /* Free up the FM.  If kFin is non-NULL, it is applied to keys
   1427    before the FM is deleted; ditto with vFin for vals. */
   1428 void deleteFM ( WordFM* fm, void(*kFin)(Word), void(*vFin)(Word) )
   1429 {
   1430    void(*dealloc)(void*) = fm->dealloc;
   1431    avl_free( fm->root, kFin, vFin, dealloc );
   1432    memset(fm, 0, sizeof(WordFM) );
   1433    dealloc(fm);
   1434 }
   1435 
   1436 /* Add (k,v) to fm. */
   1437 void addToFM ( WordFM* fm, Word k, Word v )
   1438 {
   1439    MaybeWord oldV;
   1440    AvlNode* node;
   1441    node = fm->alloc_nofail( sizeof(struct _AvlNode) );
   1442    node->key = k;
   1443    node->val = v;
   1444    oldV.b = False;
   1445    oldV.w = 0;
   1446    avl_insert_wrk( &fm->root, &oldV, node, fm->kCmp );
   1447    //if (oldV.b && fm->vFin)
   1448    //   fm->vFin( oldV.w );
   1449    if (oldV.b)
   1450       free(node);
   1451 }
   1452 
   1453 // Delete key from fm, returning associated val if found
   1454 Bool delFromFM ( WordFM* fm, /*OUT*/Word* oldV, Word key )
   1455 {
   1456    AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
   1457    if (node) {
   1458       avl_remove_wrk( &fm->root, node, fm->kCmp );
   1459       if (oldV)
   1460          *oldV = node->val;
   1461       fm->dealloc(node);
   1462       return True;
   1463    } else {
   1464       return False;
   1465    }
   1466 }
   1467 
   1468 // Look up in fm, assigning found val at spec'd address
   1469 Bool lookupFM ( WordFM* fm, /*OUT*/Word* valP, Word key )
   1470 {
   1471    AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
   1472    if (node) {
   1473       if (valP)
   1474          *valP = node->val;
   1475       return True;
   1476    } else {
   1477       return False;
   1478    }
   1479 }
   1480 
   1481 Word sizeFM ( WordFM* fm )
   1482 {
   1483    // Hmm, this is a bad way to do this
   1484    return fm->root ? size_avl_nonNull( fm->root ) : 0;
   1485 }
   1486 
   1487 // set up FM for iteration
   1488 void initIterFM ( WordFM* fm )
   1489 {
   1490    assert(fm);
   1491    stackClear(fm);
   1492    if (fm->root)
   1493       stackPush(fm, fm->root, 1);
   1494 }
   1495 
   1496 // get next key/val pair.  Will assert if fm has been modified
   1497 // or looked up in since initIterFM was called.
   1498 Bool nextIterFM ( WordFM* fm, /*OUT*/Word* pKey, /*OUT*/Word* pVal )
   1499 {
   1500    Int i = 0;
   1501    AvlNode* n = NULL;
   1502 
   1503    assert(fm);
   1504 
   1505    // This in-order traversal requires each node to be pushed and popped
   1506    // three times.  These could be avoided by updating nodes in-situ on the
   1507    // top of the stack, but the push/pop cost is so small that it's worth
   1508    // keeping this loop in this simpler form.
   1509    while (stackPop(fm, &n, &i)) {
   1510       switch (i) {
   1511       case 1:
   1512          stackPush(fm, n, 2);
   1513          if (n->left)  stackPush(fm, n->left, 1);
   1514          break;
   1515       case 2:
   1516          stackPush(fm, n, 3);
   1517          if (pKey) *pKey = n->key;
   1518          if (pVal) *pVal = n->val;
   1519          return True;
   1520       case 3:
   1521          if (n->right) stackPush(fm, n->right, 1);
   1522          break;
   1523       default:
   1524          assert(0);
   1525       }
   1526    }
   1527 
   1528    // Stack empty, iterator is exhausted, return NULL
   1529    return False;
   1530 }
   1531 
   1532 // clear the I'm iterating flag
   1533 void doneIterFM ( WordFM* fm )
   1534 {
   1535 }
   1536 
   1537 WordFM* dopyFM ( WordFM* fm, Word(*dopyK)(Word), Word(*dopyV)(Word) )
   1538 {
   1539    WordFM* nyu;
   1540 
   1541    /* can't clone the fm whilst iterating on it */
   1542    assert(fm->stackTop == 0);
   1543 
   1544    nyu = fm->alloc_nofail( sizeof(WordFM) );
   1545    assert(nyu);
   1546 
   1547    *nyu = *fm;
   1548 
   1549    fm->stackTop = 0;
   1550    memset(fm->nodeStack, 0, sizeof(fm->nodeStack));
   1551    memset(fm->numStack, 0,  sizeof(fm->numStack));
   1552 
   1553    if (nyu->root) {
   1554       nyu->root = avl_dopy( nyu->root, dopyK, dopyV, fm->alloc_nofail );
   1555       if (! nyu->root)
   1556          return NULL;
   1557    }
   1558 
   1559    return nyu;
   1560 }
   1561 
   1562 //------------------------------------------------------------------//
   1563 //---                         end WordFM                         ---//
   1564 //---                       Implementation                       ---//
   1565 //------------------------------------------------------------------//
   1566 
   1567 /*--------------------------------------------------------------------*/
   1568 /*--- end                                               cg_merge.c ---*/
   1569 /*--------------------------------------------------------------------*/
   1570