Added more counters. Reduced number of danger set updates slightly.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7856 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_thread.c b/exp-drd/drd_thread.c
index fc4e363..2737b13 100644
--- a/exp-drd/drd_thread.c
+++ b/exp-drd/drd_thread.c
@@ -51,6 +51,8 @@
 static ULong s_context_switch_count;
 static ULong s_discard_ordered_segments_count;
 static ULong s_update_danger_set_count;
+static ULong s_danger_set_new_segment_count;
+static ULong s_danger_set_combine_vc_count;
 static ULong s_danger_set_bitmap_creation_count;
 static ULong s_danger_set_bitmap2_creation_count;
 static ThreadId    s_vg_running_tid  = VG_INVALID_THREADID;
@@ -599,28 +601,91 @@
   }
 }
 
+/** Every change in the vector clock of a thread may cause segments that
+ *  were previously ordered to this thread to become unordered. Hence,
+ *  it may be necessary to recalculate the danger set if the vector clock 
+ *  of the current thread is updated. This function check whether such a
+ *  recalculation is necessary.
+ *
+ *  @param tid    Thread ID of the thread to which a new segment has been
+ *                appended.
+ *  @param new_sg Pointer to the most recent segment of thread tid.
+ */
+static Bool danger_set_update_needed(const DrdThreadId tid,
+                                     const Segment* const new_sg)
+{
+  unsigned i;
+  const Segment* old_sg;
+
+  tl_assert(new_sg);
+
+  /* If a new segment was added to another thread than the running thread, */
+  /* just tell the caller to update the danger set.                        */
+  if (tid != s_drd_running_tid)
+    return True;
+
+  /* Always let the caller update the danger set after creation of the */
+  /* first segment.                                                    */
+  old_sg = new_sg->prev;
+  if (old_sg == 0)
+    return True;
+
+  for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
+  {
+    Segment* q;
+
+    if (i == s_drd_running_tid)
+      continue;
+
+    for (q = s_threadinfo[i].last; q; q = q->prev)
+    {
+      /* If the expression below evaluates to false, this expression will */
+      /* also evaluate to false for all subsequent iterations. So stop    */
+      /* iterating.                                                       */
+      if (vc_lte(&q->vc, &old_sg->vc))
+        break;
+      /* If the vector clock of the 2nd the last segment is not ordered   */
+      /* to the vector clock of segment q, and the last segment is, ask   */
+      /* the caller to update the danger set.                             */
+      if (! vc_lte(&old_sg->vc, &q->vc))
+      {
+        return True;
+      }
+      /* If the vector clock of the last segment is not ordered to the    */
+      /* vector clock of segment q, ask the caller to update the danger   */
+      /* set.                                                             */
+      if (! vc_lte(&q->vc, &new_sg->vc) && ! vc_lte(&new_sg->vc, &q->vc))
+      {
+        return True;
+      }
+    }
+  }
+
+  return False;
+}
+
 /** Create a new segment for the specified thread, and discard any segments
  *  that cannot cause races anymore.
  */
 void thread_new_segment(const DrdThreadId tid)
 {
+  Segment* new_sg;
+
   tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
 
-  thread_append_segment(tid, sg_new(tid, tid));
+  new_sg = sg_new(tid, tid);
+  thread_append_segment(tid, new_sg);
+
+  if (danger_set_update_needed(tid, new_sg))
+  {
+    thread_update_danger_set(s_drd_running_tid);
+    s_danger_set_new_segment_count++;
+  }
 
   thread_discard_ordered_segments();
 
   if (s_segment_merging)
     thread_merge_segments();
-
-  if (tid == s_drd_running_tid)
-  {
-    /* Every change in the vector clock of the current thread may cause */
-    /* segments that were previously ordered to this thread to become   */
-    /* unordered. Hence, recalculate the danger set if the vector clock */
-    /* of the current thread is updated.                                */
-    thread_update_danger_set(tid);
-  }
 }
 
 /** Call this function after thread 'joiner' joined thread 'joinee'. */
@@ -652,7 +717,9 @@
   tl_assert(s_threadinfo[tid].last);
   tl_assert(vc);
   vc_combine(&s_threadinfo[tid].last->vc, vc);
+  thread_update_danger_set(tid);
   thread_discard_ordered_segments();
+  s_danger_set_combine_vc_count++;
 }
 
 /** Call this function whenever a thread is no longer using the memory
@@ -873,12 +940,12 @@
 
     for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
     {
-      if (IsValidDrdThreadId(j))
+      if (j != tid && IsValidDrdThreadId(j))
       {
         const Segment* q;
         for (q = s_threadinfo[j].last; q; q = q->prev)
-          if (j != tid && q != 0
-              && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
+        {
+          if (! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
           {
             if (s_trace_danger_set)
             {
@@ -905,6 +972,7 @@
               VG_(message)(Vg_UserMsg, "%s", msg);
             }
           }
+        }
       }
     }
   }
@@ -930,8 +998,12 @@
   return s_discard_ordered_segments_count;
 }
 
-ULong thread_get_update_danger_set_count(void)
+ULong thread_get_update_danger_set_count(ULong* dsnsc, ULong* dscvc)
 {
+  tl_assert(dsnsc);
+  tl_assert(dscvc);
+  *dsnsc = s_danger_set_new_segment_count;
+  *dscvc = s_danger_set_combine_vc_count;
   return s_update_danger_set_count;
 }