List:Commits« Previous MessageNext Message »
From:Vladislav Vaintroub Date:September 6 2010 9:09pm
Subject:bzr commit into mysql-trunk branch (vvaintroub:3193) Bug#56585
View as plain text  
#At file:///H:/bzr-new/trunk1/ based on revid:alik@stripped

 3193 Vladislav Vaintroub	2010-09-06
      Bug#56585: Slowdown of readonly sysbench benchmarks (e.g
      point_select) 
      
      This is a test patch , based on discussions with Dmitry: implement 
      condition variable on top of Vista native conditions, on Vista and later.
      
      This way, existing code for "reader prefered" locks can be reused,
      accounting for all prefer-readefr specifics (recursive locks etc)
      while overhead of using OS events is reduced.
      
      However, judging by benchmarks that compare native rwlock 
      to the one implemented on top of native condition to the one
      implemented on top of events, the gain of using native condition
      is minimal,while the gain using native rwlocks would be big.
      
      Following table illustrates the results of  benchmarks
      (sysbench, 2 readonly tests- simple ranges and point_select
      256 users, 8 core machine)
      
      benchmark     |  no-fix |  native rwlock |  native condition
      --------------------------------------------------------------------
      simple_ranges| 14051   | 17996           | 13906               |
      -------------------------------------------------------------------
      point_select   | 20576   | 29120           | 22961               |
      -------------------------------------------------------------------

    modified:
      include/my_pthread.h
      mysys/my_wincond.c
=== modified file 'include/my_pthread.h'
--- a/include/my_pthread.h	2010-08-20 08:48:59 +0000
+++ b/include/my_pthread.h	2010-09-06 21:09:45 +0000
@@ -49,6 +49,8 @@ typedef struct st_pthread_link {
 } pthread_link;
 
 typedef struct {
+  /* Native condition used on newer Windows (Vista+) */
+  CONDITION_VARIABLE cond;
   uint32 waiting;
   CRITICAL_SECTION lock_waiting;
  

=== modified file 'mysys/my_wincond.c'
--- a/mysys/my_wincond.c	2009-11-23 17:08:37 +0000
+++ b/mysys/my_wincond.c	2010-09-06 21:09:45 +0000
@@ -24,7 +24,197 @@
 #include <process.h>
 #include <sys/timeb.h>
 
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+
+/* Windows native condition variables. We use runtime loading / function 
+  pointers, because they are not available on XP */
+
+/* Prototypes and function pointers for condition variable functions */
+typedef VOID (WINAPI * InitializeConditionVariableProc) 
+  (PCONDITION_VARIABLE ConditionVariable);
+static InitializeConditionVariableProc my_InitializeConditionVariable;
+
+typedef BOOL (WINAPI * SleepConditionVariableCSProc)
+  (PCONDITION_VARIABLE ConditionVariable,
+  PCRITICAL_SECTION CriticalSection, 
+  DWORD dwMilliseconds);
+static SleepConditionVariableCSProc my_SleepConditionVariableCS;
+
+typedef VOID (WINAPI * WakeAllConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+static WakeAllConditionVariableProc my_WakeAllConditionVariable;
+
+typedef VOID (WINAPI * WakeConditionVariableProc)
+  (PCONDITION_VARIABLE ConditionVariable);
+static WakeConditionVariableProc my_WakeConditionVariable;
+
+/* 
+ This functions are only called in case of programming errors 
+ (first call to pthread_cond_xxx is not pthread_cond_init)
+*/
+static int bad_condition_function(pthread_cond_t *a)
+{
+  abort();
+  return 0;
+}
+
+static int bad_timedwait_func(pthread_cond_t *a, pthread_mutex_t *b, 
+  struct timespec *c)
+{
+  abort();
+  return 0;
+}
+
+/* 
+  condition implementation function pointes (initialized at first call of
+  pthread_cond_init). Programming errors (calling function different from
+  pthread_cond_init() first, will be punished with abort()
+*/
+static int cond_init_first_call(pthread_cond_t *, const pthread_condattr_t *);
+static int (*cond_init_impl)(pthread_cond_t *,const pthread_condattr_t *)= cond_init_first_call;
+
+static int (*cond_destroy_impl)(pthread_cond_t *) = bad_condition_function;
+static int (*cond_signal_impl)(pthread_cond_t *) = bad_condition_function;
+static int (*cond_broadcast_impl)(pthread_cond_t *) = bad_condition_function;
+static int (*cond_timedwait_impl)(pthread_cond_t *, pthread_mutex_t *, 
+  struct timespec *) = bad_timedwait_func;
+
+
+/* Native implementation (Vista and later) */
+static int native_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+static int native_cond_destroy(pthread_cond_t *);
+static int native_cond_signal(pthread_cond_t *);
+static int native_cond_broadcast(pthread_cond_t *);
+static int native_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, 
+  struct timespec *);
+
+/* Old implementation (pre-Vista) */
+static int old_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+static int old_cond_destroy(pthread_cond_t *);
+static int old_cond_signal(pthread_cond_t *);
+static int old_cond_broadcast(pthread_cond_t *);
+static int old_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, 
+  struct timespec *);
+
+
+
+/*
+ Initialized implementation of condition variables, chooses between
+ native implementation if Windows version supports it or legacy implementation
+ if not.
+*/
+static void load_function_pointers(void)
+{
+  HMODULE dll;
+  dll = GetModuleHandle("kernel32");
+
+  my_InitializeConditionVariable = (InitializeConditionVariableProc)
+    GetProcAddress(dll, "InitializeConditionVariable");
+  my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
+    GetProcAddress(dll, "SleepConditionVariableCS");
+  my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
+    GetProcAddress(dll, "WakeAllConditionVariable");
+  my_WakeConditionVariable= (WakeConditionVariableProc)
+    GetProcAddress(dll, "WakeConditionVariable");
+  
+  if(my_InitializeConditionVariable)
+  {
+    cond_init_impl= native_cond_init;
+    cond_destroy_impl= native_cond_destroy;
+    cond_broadcast_impl= native_cond_broadcast;
+    cond_signal_impl= native_cond_signal;
+    cond_timedwait_impl= native_cond_timedwait;
+  }
+  else
+  {
+    cond_init_impl= old_cond_init;
+    cond_destroy_impl= old_cond_destroy;
+    cond_broadcast_impl= old_cond_broadcast;
+    cond_signal_impl= old_cond_signal;
+    cond_timedwait_impl= old_cond_timedwait;
+  }
+}
+
+static DWORD get_milliseconds(const struct timespec *abstime)
+{
+  DWORD millis; 
+  union ft64 now;
+
+  if( abstime != NULL )
+  {
+    GetSystemTimeAsFileTime(&now.ft);
+
+    /*
+      Calculate time left to abstime
+      - subtract start time from current time(values are in 100ns units)
+      - convert to millisec by dividing with 10000
+    */
+    millis = (DWORD)((abstime->tv.i64 - now.i64) / 10000);
+    
+    /* Don't allow the timeout to be negative */
+    if (millis < 0)
+      millis= 0L;
+
+    /*
+      Make sure the calucated timeout does not exceed original timeout
+      value which could cause "wait for ever" if system time changes
+    */
+    if (millis > (DWORD)abstime->max_timeout_msec)
+      millis= abstime->max_timeout_msec;
+
+  }
+  else
+  {
+    /* No time specified; don't expire */
+    millis= INFINITE;
+  }
+  return millis;
+}
+
+/*
+  Implementation with native conditions 
+*/
+
+static int native_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+  my_InitializeConditionVariable(&cond->cond);
+  return 0;
+}
+
+
+static int native_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+   struct timespec *abstime)
+{
+  DWORD timeout = get_milliseconds(abstime);
+
+  if(!my_SleepConditionVariableCS(&cond->cond, mutex, timeout))
+    return ETIMEDOUT;
+
+  return 0;
+}
+
+
+int native_cond_signal(pthread_cond_t *cond)
+{
+  my_WakeConditionVariable(&cond->cond);
+  return 0;
+}
+
+int native_cond_broadcast(pthread_cond_t *cond)
+{
+  my_WakeAllConditionVariable(&cond->cond);
+  return 0;
+}
+
+int native_cond_destroy(pthread_cond_t *cond)
+{
+  return 0;
+}
+
+
+/*
+  old (pre-vista) implementation with using events
+*/
+static int old_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
 {
   cond->waiting= 0;
   InitializeCriticalSection(&cond->lock_waiting);
@@ -53,7 +243,7 @@ int pthread_cond_init(pthread_cond_t *co
   return 0;
 }
 
-int pthread_cond_destroy(pthread_cond_t *cond)
+static int old_cond_destroy(pthread_cond_t *cond)
 {
   DeleteCriticalSection(&cond->lock_waiting);
 
@@ -65,48 +255,13 @@ int pthread_cond_destroy(pthread_cond_t 
 }
 
 
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
-  return pthread_cond_timedwait(cond,mutex,NULL);
-}
-
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+static int old_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                            struct timespec *abstime)
 {
   int result;
   long timeout; 
-  union ft64 now;
-
-  if( abstime != NULL )
-  {
-    GetSystemTimeAsFileTime(&now.ft);
-
-    /*
-      Calculate time left to abstime
-      - subtract start time from current time(values are in 100ns units)
-      - convert to millisec by dividing with 10000
-    */
-    timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
-    
-    /* Don't allow the timeout to be negative */
-    if (timeout < 0)
-      timeout= 0L;
-
-    /*
-      Make sure the calucated timeout does not exceed original timeout
-      value which could cause "wait for ever" if system time changes
-    */
-    if (timeout > abstime->max_timeout_msec)
-      timeout= abstime->max_timeout_msec;
-
-  }
-  else
-  {
-    /* No time specified; don't expire */
-    timeout= INFINITE;
-  }
 
+  timeout= get_milliseconds(abstime);
   /* 
     Block access if previous broadcast hasn't finished.
     This is just for safety and should normally not
@@ -142,7 +297,7 @@ int pthread_cond_timedwait(pthread_cond_
   return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
 }
 
-int pthread_cond_signal(pthread_cond_t *cond)
+static int old_cond_signal(pthread_cond_t *cond)
 {
   EnterCriticalSection(&cond->lock_waiting);
   
@@ -155,7 +310,7 @@ int pthread_cond_signal(pthread_cond_t *
 }
 
 
-int pthread_cond_broadcast(pthread_cond_t *cond)
+static int old_cond_broadcast(pthread_cond_t *cond)
 {
   EnterCriticalSection(&cond->lock_waiting);
   /*
@@ -177,6 +332,46 @@ int pthread_cond_broadcast(pthread_cond_
 }
 
 
+static int cond_init_first_call(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+  static my_pthread_once_t once_control = MY_PTHREAD_ONCE_INIT;
+  my_pthread_once(&once_control, load_function_pointers);
+  return cond_init_impl(cond, attr);
+}
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+  return cond_init_impl(cond, attr);
+}
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+  return cond_destroy_impl(cond);
+}
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+  return cond_broadcast_impl(cond);
+}
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+  return cond_signal_impl(cond);
+}
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+  struct timespec *abstime)
+{
+  return cond_timedwait_impl(cond, mutex, abstime);
+}
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+  return cond_timedwait_impl(cond, mutex, NULL);
+}
+
+
+
 int pthread_attr_init(pthread_attr_t *connect_att)
 {
   connect_att->dwStackSize	= 0;


Attachment: [text/bzr-bundle] bzr/vvaintroub@mysql.com-20100906210945-k8ra72qjaja5ccrz.bundle
Thread
bzr commit into mysql-trunk branch (vvaintroub:3193) Bug#56585Vladislav Vaintroub6 Sep