Avoid divisions by zero.  This fixes bug 78765.

Also renamed two of the XPt fields so that things are clearer.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2628 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 74a0e4d..1e45ae6 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -100,13 +100,13 @@
    // An approximate space.time calculation used along the way for selecting
    // which contexts to include at each census point.
    // !!! top-XPTs only !!!
-   ULong spacetime; 
+   ULong approx_ST;
 
-   // spacetime2 is an exact space.time calculation done at the end, and
+   // exact_ST_dbld is an exact space.time calculation done at the end, and
    // used in the results.
    // Note that it is *doubled*, to avoid rounding errors.
    // !!! not used for 'alloc_xpt' !!!
-   ULong spacetime2;
+   ULong exact_ST_dbld;
 
    // n_children and max_children are integers;  a very big program might
    // have more than 65536 allocation points (Konqueror startup has 1800).
@@ -120,7 +120,7 @@
 // top-XPt as its root.  The 'curr_space' element for each XPt is recorded 
 // in the snapshot.  The snapshot contains all the XTree's XPts, not in a
 // tree structure, but flattened into an array.  This flat snapshot is used
-// at the end for computing spacetime2 for each XPt.
+// at the end for computing exact_ST_dbld for each XPt.
 //
 // Graph resolution, x-axis: no point having more than about 200 census
 // x-points;  you can't see them on the graph.  Therefore:
@@ -368,9 +368,9 @@
    XPt* xpt          = perm_malloc(sizeof(XPt));
    xpt->eip          = eip;
 
-   xpt->curr_space   = 0;
-   xpt->spacetime    = 0;
-   xpt->spacetime2   = 0;
+   xpt->curr_space    = 0;
+   xpt->approx_ST     = 0;
+   xpt->exact_ST_dbld = 0;
 
    xpt->parent       = parent;
 
@@ -438,8 +438,8 @@
       // run out of %eips before hitting clo_depth.  It's done to ensure the
       // XPt we return is (now and forever) a bottom-XPt.  If the returned XPt
       // wasn't a bottom-XPt (now or later) it would cause problems later (eg.
-      // the parent's spacetime wouldn't be equal to the total of the
-      // childrens' spacetimes).  
+      // the parent's approx_ST wouldn't be equal [or almost equal] to the
+      // total of the childrens' approx_STs).  
       eips[ n_eips++ ] = 0xffffffff;
 
       // Skip over alloc functions in eips[]. 
@@ -536,18 +536,18 @@
 }
 
 // Actually want a reverse sort, biggest to smallest
-static Int XPt_cmp_spacetime(void* n1, void* n2)
+static Int XPt_cmp_approx_ST(void* n1, void* n2)
 {
    XPt* xpt1 = *(XPt**)n1;
    XPt* xpt2 = *(XPt**)n2;
-   return (xpt1->spacetime < xpt2->spacetime ? 1 : -1);
+   return (xpt1->approx_ST < xpt2->approx_ST ? 1 : -1);
 }
 
-static Int XPt_cmp_spacetime2(void* n1, void* n2)
+static Int XPt_cmp_exact_ST_dbld(void* n1, void* n2)
 {
    XPt* xpt1 = *(XPt**)n1;
    XPt* xpt2 = *(XPt**)n2;
-   return (xpt1->spacetime2 < xpt2->spacetime2 ? 1 : -1);
+   return (xpt1->exact_ST_dbld < xpt2->exact_ST_dbld ? 1 : -1);
 }
 
 
@@ -858,12 +858,12 @@
 {
    UInt i;
 
-//   VG_(printf)("%4d ", xpt->curr_space);
-
-   // If this one has size zero, all the children will be size zero too, so
-   // nothing interesting to record.
-//   if (0 != xpt->curr_space || 0 == ix) {
-   if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002 || 0 == ix) {
+   // If no memory allocated at all, nothing interesting to record.
+   if (alloc_xpt->curr_space == 0) return 0;
+   
+   // Ignore sub-XTrees that account for a miniscule fraction of current
+   // allocated space.
+   if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002) {
       ix++;
 
       // Count all (non-zero) descendent XPts
@@ -878,14 +878,15 @@
 {
    UInt i;
 
-   // Snapshot this XPt, if non-zero space, or the first one
-//   if (0 != xpt->curr_space || 0 == ix) {
-   if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002 || 0 == ix) {
+   // Structure of this function mirrors that of get_xtree_size().
+
+   if (alloc_xpt->curr_space == 0) return 0;
+   
+   if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002) {
       xtree_snapshot[ix].xpt   = xpt;
       xtree_snapshot[ix].space = xpt->curr_space;
       ix++;
 
-      // Snapshot all (non-zero) descendent XPts
       for (i = 0; i < xpt->n_children; i++)
          ix = do_space_snapshot(xpt->children[i], xtree_snapshot, ix);
    }
@@ -1007,15 +1008,15 @@
           ? alloc_xpt->n_children
           : MAX_SNAPSHOTS);     // max out
 
-      // Update .spacetime field (approximatively) for all top-XPts.
+      // Update .approx_ST field (approximatively) for all top-XPts.
       // We *do not* do it for any non-top-XPTs.
       for (i = 0; i < alloc_xpt->n_children; i++) {
          XPt* top_XPt = alloc_xpt->children[i];
-         top_XPt->spacetime += top_XPt->curr_space * ms_time_since_prev;
+         top_XPt->approx_ST += top_XPt->curr_space * ms_time_since_prev;
       }
-      // Sort top-XPts by spacetime2 field.
+      // Sort top-XPts by approx_ST field.
       VG_(ssort)(alloc_xpt->children, alloc_xpt->n_children, sizeof(XPt*),
-                 XPt_cmp_spacetime);
+                 XPt_cmp_approx_ST);
 
       VGP_PUSHCC(VgpCensusHeap);
 
@@ -1023,15 +1024,21 @@
       // entire XTree, in a single census entry.
       // Nb: the xtree_size count/snapshot buffer allocation, and the actual
       // snapshot, take similar amounts of time (measured with the
-      // millesecond counter).
+      // millisecond counter).
       for (i = 0; i < K; i++) {
          UInt xtree_size, xtree_size2;
-//         VG_(printf)("%7u ", alloc_xpt->children[i]->spacetime);
-         // Count how many XPts are in the XTree;  make array of that size
-         // (+1 for zero termination, which calloc() does for us).
+//         VG_(printf)("%7u ", alloc_xpt->children[i]->approx_ST);
+         // Count how many XPts are in the XTree
          VGP_PUSHCC(VgpCensusTreeSize);
          xtree_size = get_xtree_size( alloc_xpt->children[i], 0 );
          VGP_POPCC(VgpCensusTreeSize);
+
+         // If no XPts counted (ie. alloc_xpt.curr_space==0 or XTree
+         // insignificant) then don't take any more snapshots.
+         if (0 == xtree_size) break;
+         
+         // Make array of the appropriate size (+1 for zero termination,
+         // which calloc() does for us).
          census->xtree_snapshots[i] =
             VG_(calloc)(xtree_size+1, sizeof(XPtSnapshot));
          if (0 && VG_(clo_verbosity) > 1)
@@ -1041,7 +1048,7 @@
          // Take space-snapshot: copy 'curr_space' for every XPt in the
          // XTree into the snapshot array, along with pointers to the XPts.
          // (Except for ones with curr_space==0, which wouldn't contribute
-         // to the final spacetime2 calculation anyway;  excluding them
+         // to the final exact_ST_dbld calculation anyway;  excluding them
          // saves a lot of memory and up to 40% time with big --depth valus.
          VGP_PUSHCC(VgpCensusSnapshot);
          xtree_size2 = do_space_snapshot(alloc_xpt->children[i],
@@ -1179,7 +1186,7 @@
    VGP_(register_profile_event)(VgpCensusSnapshot, "census-snapshot");
    VGP_(register_profile_event)(VgpCensusTreeSize, "census-treesize");
    VGP_(register_profile_event)(VgpUpdateXCon,     "update-XCon");
-   VGP_(register_profile_event)(VgpCalcSpacetime2, "calc-spacetime2");
+   VGP_(register_profile_event)(VgpCalcSpacetime2, "calc-exact_ST_dbld");
    VGP_(register_profile_event)(VgpPrintHp,        "print-hp");
    VGP_(register_profile_event)(VgpPrintXPts,      "print-XPts");
 
@@ -1213,15 +1220,15 @@
 /*--- Spacetime recomputation                              ---*/
 /*------------------------------------------------------------*/
 
-// Although we've been calculating spacetime along the way, because the
-// earlier calculations were done at a finer timescale, the .spacetime field
+// Although we've been calculating space-time along the way, because the
+// earlier calculations were done at a finer timescale, the .approx_ST field
 // might not agree with what hp2ps sees, because we've thrown away some of
 // the information.  So recompute it at the scale that hp2ps sees, so we can
 // confidently determine which contexts hp2ps will choose for displaying as
 // distinct bands.  This recomputation only happens to the significant ones
 // that get printed in the .hp file, so it's cheap.
 //
-// The spacetime calculation: 
+// The approx_ST calculation: 
 //   ( a[0]*d(0,1) + a[1]*(d(0,1) + d(1,2)) + ... + a[N-1]*d(N-2,N-1) ) / 2
 //   where
 //   a[N] is the space at census N
@@ -1236,11 +1243,11 @@
 // AP is a pain with this data structure, but getting the prev/next
 // census time is easy.
 //
-// Each heap calculation gets added to its context's spacetime2 field.
+// Each heap calculation gets added to its context's exact_ST_dbld field.
 // The ULong* values are all running totals, hence the use of "+=" everywhere.
 
 // This does the calculations for a single census.
-static void calc_spacetime2b(Census* census, UInt d_t1_t2,
+static void calc_exact_ST_dbld2(Census* census, UInt d_t1_t2,
                              ULong* twice_heap_ST,
                              ULong* twice_heap_admin_ST,
                              ULong* twice_stack_ST)
@@ -1251,14 +1258,15 @@
    // Heap --------------------------------------------------------
    if (clo_heap) {
       for (i = 0; NULL != census->xtree_snapshots[i]; i++) {
-         // Compute total heap spacetime2 for the entire XTree using only the
-         // top-XPt (the first XPt in xtree_snapshot).
+         // Compute total heap exact_ST_dbld for the entire XTree using only
+         // the top-XPt (the first XPt in xtree_snapshot).
          *twice_heap_ST += d_t1_t2 * census->xtree_snapshots[i][0].space;
 
-         // Increment spacetime2 for every XPt in xtree_snapshot (inc. top one)
+         // Increment exact_ST_dbld for every XPt in xtree_snapshot (inc.
+         // top one)
          for (j = 0; NULL != census->xtree_snapshots[i][j].xpt; j++) {
             xpt_snapshot = & census->xtree_snapshots[i][j];
-            xpt_snapshot->xpt->spacetime2 += d_t1_t2 * xpt_snapshot->space;
+            xpt_snapshot->xpt->exact_ST_dbld += d_t1_t2 * xpt_snapshot->space;
          }
       }
       *twice_heap_ST += d_t1_t2 * census->others_space;
@@ -1274,7 +1282,7 @@
 }
 
 // This does the calculations for all censi.
-static void calc_spacetime2(ULong* heap2, ULong* heap_admin2, ULong* stack2)
+static void calc_exact_ST_dbld(ULong* heap2, ULong* heap_admin2, ULong* stack2)
 {
    UInt i, N = curr_census;
 
@@ -1287,16 +1295,16 @@
    if (N <= 1)
       return;
 
-   calc_spacetime2b( &censi[0], censi[1].ms_time - censi[0].ms_time,
-                     heap2, heap_admin2, stack2 );
+   calc_exact_ST_dbld2( &censi[0], censi[1].ms_time - censi[0].ms_time,
+                        heap2, heap_admin2, stack2 );
 
    for (i = 1; i <= N-2; i++) {
-      calc_spacetime2b( & censi[i], censi[i+1].ms_time - censi[i-1].ms_time,
-                        heap2, heap_admin2, stack2 );
+      calc_exact_ST_dbld2( & censi[i], censi[i+1].ms_time - censi[i-1].ms_time,
+                           heap2, heap_admin2, stack2 );
    }
 
-   calc_spacetime2b( & censi[N-1], censi[N-1].ms_time - censi[N-2].ms_time,
-                     heap2, heap_admin2, stack2 ); 
+   calc_exact_ST_dbld2( & censi[N-1], censi[N-1].ms_time - censi[N-2].ms_time,
+                        heap2, heap_admin2, stack2 ); 
    // Now get rid of the halves.  May lose a 0.5 on each, doesn't matter.
    *heap2       /= 2;
    *heap_admin2 /= 2;
@@ -1498,6 +1506,7 @@
    static Char mbuf[32];
    
    UInt  p = 10;
+   sk_assert(0 != total_spacetime);
    percentify(spacetime * 100 * p / total_spacetime, p, 5, mbuf); 
    return mbuf;
 }
@@ -1560,29 +1569,35 @@
                                  "=================================" );
    Char* depth     = ( is_HTML ? "<code>--depth</code>" : "--depth" );
 
+   if (total_spacetime == 0) {
+      SPRINTF(buf, "(No heap memory allocated)\n");
+      return;
+   }
+
+
    SPRINTF(buf, "== %d ===========================%s\n", L, maybe_br);
 
    while (NULL != (xpt = (XPt*)dequeue(q))) {
-      // Check that non-top-level XPts have a zero .spacetime field.
-      if (xpt->parent != alloc_xpt) sk_assert( 0 == xpt->spacetime );
+      // Check that non-top-level XPts have a zero .approx_ST field.
+      if (xpt->parent != alloc_xpt) sk_assert( 0 == xpt->approx_ST );
 
-      // Check that the sum of all children .spacetime2s equals parent's
-      // (unless alloc_xpt, when it should == 0).
+      // Check that the sum of all children .exact_ST_dbld fields equals
+      // parent's (unless alloc_xpt, when it should == 0).
       if (alloc_xpt == xpt) {
-         sk_assert(0 == xpt->spacetime2);
+         sk_assert(0 == xpt->exact_ST_dbld);
       } else {
          sum = 0;
          for (i = 0; i < xpt->n_children; i++) {
-            sum += xpt->children[i]->spacetime2;
+            sum += xpt->children[i]->exact_ST_dbld;
          }
-         //sk_assert(sum == xpt->spacetime2);
+         //sk_assert(sum == xpt->exact_ST_dbld);
          // It's possible that not all the children were included in the
-         // spacetime2 calculations.  Hopefully almost all of them were, and
+         // exact_ST_dbld calculations.  Hopefully almost all of them were, and
          // all the important ones.
-//         sk_assert(sum <= xpt->spacetime2);
-//         sk_assert(sum * 1.05 > xpt->spacetime2 );
-//         if (sum != xpt->spacetime2) {
-//            VG_(printf)("%ld, %ld\n", sum, xpt->spacetime2);
+//         sk_assert(sum <= xpt->exact_ST_dbld);
+//         sk_assert(sum * 1.05 > xpt->exact_ST_dbld );
+//         if (sum != xpt->exact_ST_dbld) {
+//            VG_(printf)("%ld, %ld\n", sum, xpt->exact_ST_dbld);
 //         }
       }
 
@@ -1591,8 +1606,8 @@
                       "%s of measured spacetime%s\n", 
                       make_perc(heap_spacetime, total_spacetime), maybe_br);
       } else {
-         // Remember: spacetime2 is space.time *doubled*
-         perc = make_perc(xpt->spacetime2 / 2, total_spacetime);
+         // Remember: exact_ST_dbld is space.time *doubled*
+         perc = make_perc(xpt->exact_ST_dbld / 2, total_spacetime);
          if (is_HTML) {
             SPRINTF(buf, "<a name=\"b%x\"></a>"
                          "Context accounted for "
@@ -1606,16 +1621,16 @@
          sk_assert(n == L);
       }
 
-      // Sort children by spacetime2
+      // Sort children by exact_ST_dbld
       VG_(ssort)(xpt->children, xpt->n_children, sizeof(XPt*),
-                 XPt_cmp_spacetime2);
+                 XPt_cmp_exact_ST_dbld);
 
       SPRINTF(buf, "%s\nCalled from:%s\n", maybe_p, maybe_ul);
       for (i = 0; i < xpt->n_children; i++) {
          child = xpt->children[i];
 
          // Stop when <1% of total spacetime
-         if (child->spacetime2 * 1000 / (total_spacetime * 2) < 5) {
+         if (child->exact_ST_dbld * 1000 / (total_spacetime * 2) < 5) {
             UInt  n_insig = xpt->n_children - i;
             Char* s       = ( n_insig == 1 ? "" : "s" );
             Char* and     = ( 0 == i ? "" : "and "   );
@@ -1625,8 +1640,8 @@
             break;
          }
 
-         // Remember: spacetime2 is space.time *doubled*
-         perc     = make_perc(child->spacetime2 / 2, total_spacetime);
+         // Remember: exact_ST_dbld is space.time *doubled*
+         perc     = make_perc(child->exact_ST_dbld / 2, total_spacetime);
          eip_desc = VG_(describe_eip)(child->eip-1, buf2, BUF_LEN);
          if (is_HTML) {
             SPRINTF(buf, "<li><a name=\"a%x\"></a>", child );
@@ -1673,6 +1688,7 @@
                         ULong total_spacetime)
 {
    Queue* q = construct_queue(100);
+
    enqueue(q, xpt);
    pp_all_XPts2(fd, q, heap_spacetime, total_spacetime);
    destruct_queue(q);
@@ -1737,19 +1753,23 @@
    // Heap --------------------------------------------------------------
    if (clo_heap)
       VG_(message)(Vg_UserMsg, "heap:              %s",
-                   make_perc(heap_ST, total_ST) );
+                   ( 0 == total_ST ? (Char*)"(n/a)"
+                                   : make_perc(heap_ST, total_ST) ) );
 
    // Heap admin --------------------------------------------------------
    if (clo_heap_admin)
       VG_(message)(Vg_UserMsg, "heap admin:        %s", 
-                   make_perc(heap_admin_ST, total_ST));
+                   ( 0 == total_ST ? (Char*)"(n/a)"
+                                   : make_perc(heap_admin_ST, total_ST) ) );
 
    sk_assert( VG_(HT_count_nodes)(malloc_list) == n_heap_blocks );
 
    // Stack(s) ----------------------------------------------------------
-   if (clo_stacks)
+   if (clo_stacks) {
+      sk_assert(0 != total_ST);
       VG_(message)(Vg_UserMsg, "stack(s):          %s", 
-                   make_perc(stack_ST, total_ST));
+                   make_perc(stack_ST, total_ST) );
+   }
 
    if (VG_(clo_verbosity) > 1) {
       sk_assert(n_xpts > 0);  // always have alloc_xpt
@@ -1783,7 +1803,7 @@
    hp_census();
 
    // Redo spacetimes of significant contexts to match the .hp file.
-   calc_spacetime2(&heap_ST, &heap_admin_ST, &stack_ST);
+   calc_exact_ST_dbld(&heap_ST, &heap_admin_ST, &stack_ST);
    total_ST = heap_ST + heap_admin_ST + stack_ST; 
    write_hp_file  ( );
    write_text_file( total_ST, heap_ST );