Helgrind optimisation: 
* do VTS pruning only if new threads were declared
  very dead since the last pruning round.
* When doing pruning, use the new list of threads very dead
  to do the pruning : this decreases the cost of the dichotomic search
  in VTS__substract



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15044 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/helgrind/libhb_core.c b/helgrind/libhb_core.c
index cb7e851..35472ad 100644
--- a/helgrind/libhb_core.c
+++ b/helgrind/libhb_core.c
@@ -1818,16 +1818,18 @@
 }
 
 
-/* The dead thread (ThrID, actually) table.  A thread may only be
+/* The dead thread (ThrID, actually) tables.  A thread may only be
    listed here if we have been notified thereof by libhb_async_exit.
    New entries are added at the end.  The order isn't important, but
-   the ThrID values must be unique.  This table lists the identity of
-   all threads that have ever died -- none are ever removed.  We keep
-   this table so as to be able to prune entries from VTSs.  We don't
-   actually need to keep the set of threads that have ever died --
+   the ThrID values must be unique.
+   verydead_thread_table_not_pruned lists the identity of the threads
+   that died since the previous round of pruning.
+   Once pruning is done, these ThrID are added in verydead_thread_table.
+   We don't actually need to keep the set of threads that have ever died --
    only the threads that have died since the previous round of
    pruning.  But it's useful for sanity check purposes to keep the
    entire set, so we do. */
+static XArray* /* of ThrID */ verydead_thread_table_not_pruned = NULL;
 static XArray* /* of ThrID */ verydead_thread_table = NULL;
 
 /* Arbitrary total ordering on ThrIDs. */
@@ -1839,16 +1841,40 @@
    return 0;
 }
 
-static void verydead_thread_table_init ( void )
+static void verydead_thread_tables_init ( void )
 {
    tl_assert(!verydead_thread_table);
+   tl_assert(!verydead_thread_table_not_pruned);
    verydead_thread_table
      = VG_(newXA)( HG_(zalloc),
                    "libhb.verydead_thread_table_init.1",
                    HG_(free), sizeof(ThrID) );
    VG_(setCmpFnXA)(verydead_thread_table, cmp__ThrID);
+   verydead_thread_table_not_pruned
+     = VG_(newXA)( HG_(zalloc),
+                   "libhb.verydead_thread_table_init.2",
+                   HG_(free), sizeof(ThrID) );
+   VG_(setCmpFnXA)(verydead_thread_table_not_pruned, cmp__ThrID);
 }
 
+static void verydead_thread_table_sort_and_check (XArray* thrids)
+{
+   UWord i;
+
+   VG_(sortXA)( thrids );
+   /* Sanity check: check for unique .sts.thr values. */
+   UWord nBT = VG_(sizeXA)( thrids );
+   if (nBT > 0) {
+      ThrID thrid1, thrid2;
+      thrid2 = *(ThrID*)VG_(indexXA)( thrids, 0 );
+      for (i = 1; i < nBT; i++) {
+         thrid1 = thrid2;
+         thrid2 = *(ThrID*)VG_(indexXA)( thrids, i );
+         tl_assert(thrid1 < thrid2);
+      }
+   }
+   /* Ok, so the dead thread table thrids has unique and in-order keys. */
+}
 
 /* A VTS contains .ts, its vector clock, and also .id, a field to hold
    a backlink for the caller's convenience.  Since we have no idea
@@ -2424,7 +2450,7 @@
 
    ThrID nyu;
    nyu = Thr__to_ThrID(thr);
-   VG_(addToXA)( verydead_thread_table, &nyu );
+   VG_(addToXA)( verydead_thread_table_not_pruned, &nyu );
 
    /* We can only get here if we're assured that we'll never again
       need to look at this thread's ::viR or ::viW.  Set them to
@@ -2819,26 +2845,16 @@
       quit at this point if it is not to be done. */
    if (!do_pruning)
       return;
+   /* No need to do pruning if no thread died since the last pruning as
+      no VtsTE can be pruned. */
+   if (VG_(sizeXA)( verydead_thread_table_not_pruned) == 0)
+      return;
 
    /* ---------- BEGIN VTS PRUNING ---------- */
-   /* We begin by sorting the backing table on its .thr values, so as
-      to (1) check they are unique [else something has gone wrong,
-      since it means we must have seen some Thr* exiting more than
-      once, which can't happen], and (2) so that we can quickly look
+   /* Sort and check the very dead threads that died since the last pruning.
+      Sorting is used for the check and so that we can quickly look
       up the dead-thread entries as we work through the VTSs. */
-   VG_(sortXA)( verydead_thread_table );
-   /* Sanity check: check for unique .sts.thr values. */
-   UWord nBT = VG_(sizeXA)( verydead_thread_table );
-   if (nBT > 0) {
-      ThrID thrid1, thrid2;
-      thrid2 = *(ThrID*)VG_(indexXA)( verydead_thread_table, 0 );
-      for (i = 1; i < nBT; i++) {
-         thrid1 = thrid2;
-         thrid2 = *(ThrID*)VG_(indexXA)( verydead_thread_table, i );
-         tl_assert(thrid1 < thrid2);
-      }
-   }
-   /* Ok, so the dead thread table has unique and in-order keys. */
+   verydead_thread_table_sort_and_check (verydead_thread_table_not_pruned);
 
    /* We will run through the old table, and create a new table and
       set, at the same time setting the .remap entries in the old
@@ -2897,7 +2913,7 @@
       nBeforePruning++;
       nSTSsBefore += old_vts->usedTS;
       VTS* new_vts = VTS__subtract("libhb.vts_tab__do_GC.new_vts",
-                                   old_vts, verydead_thread_table);
+                                   old_vts, verydead_thread_table_not_pruned);
       tl_assert(new_vts->sizeTS == new_vts->usedTS);
       tl_assert(*(ULong*)(&new_vts->ts[new_vts->usedTS])
                 == 0x0ddC0ffeeBadF00dULL);
@@ -2957,6 +2973,21 @@
 
    } /* for (i = 0; i < nTab; i++) */
 
+   /* Move very dead thread from verydead_thread_table_not_pruned to
+      verydead_thread_table. Sort and check verydead_thread_table
+      to verify a thread was reported very dead only once. */
+   {
+      UWord nBT = VG_(sizeXA)( verydead_thread_table_not_pruned);
+
+      for (i = 0; i < nBT; i++) {
+         ThrID thrid = 
+            *(ThrID*)VG_(indexXA)( verydead_thread_table_not_pruned, i );
+         VG_(addToXA)( verydead_thread_table, &thrid );
+      }
+      verydead_thread_table_sort_and_check (verydead_thread_table);
+      VG_(dropHeadXA) (verydead_thread_table_not_pruned, nBT);
+   }
+
    /* At this point, we have:
       * the old VTS table, with its .remap entries set,
         and with all .vts == NULL.
@@ -3109,11 +3140,6 @@
          nAfterPruning, nSTSsAfter / (nAfterPruning ? nAfterPruning : 1)
       );
    }
-   if (0)
-   VG_(printf)("VTQ: before pruning %lu (avg sz %lu), "
-               "after pruning %lu (avg sz %lu)\n",
-               nBeforePruning, nSTSsBefore / nBeforePruning,
-               nAfterPruning, nSTSsAfter / nAfterPruning);
    /* ---------- END VTS PRUNING ---------- */
 }
 
@@ -6080,7 +6106,7 @@
       VTS singleton, tick and join operations. */
    temp_max_sized_VTS = VTS__new( "libhb.libhb_init.1", ThrID_MAX_VALID );
    temp_max_sized_VTS->id = VtsID_INVALID;
-   verydead_thread_table_init();
+   verydead_thread_tables_init();
    vts_set_init();
    vts_tab_init();
    event_map_init();
@@ -6257,6 +6283,13 @@
                      " exit %d joinedwith %d\n",
                      live, llexit_and_joinedwith_done,
                      llexit_done, joinedwith_done);
+         VG_(printf)("   libhb: %d verydead_threads, "
+                     "%d verydead_threads_not_pruned\n",
+                     (int) VG_(sizeXA)( verydead_thread_table),
+                     (int) VG_(sizeXA)( verydead_thread_table_not_pruned));
+         tl_assert (VG_(sizeXA)( verydead_thread_table)
+                    + VG_(sizeXA)( verydead_thread_table_not_pruned)
+                    == llexit_and_joinedwith_done);
       }
 
       VG_(printf)("%s","\n");