[beast: 3/6] BSE: make bse_engine_const_values thread safe and simplify implementation



commit d880d2ac3c778260c0c39ef03cd992a78cd0ad58
Author: Tim Janik <timj gnu org>
Date:   Sun Nov 6 21:31:43 2016 +0100

    BSE: make bse_engine_const_values thread safe and simplify implementation
    
    Signed-off-by: Tim Janik <timj gnu org>

 bse/bseengine.hh      |    4 +-
 bse/bseengineutils.cc |  169 ++++++++-----------------------------------------
 bse/bseengineutils.hh |    3 +-
 3 files changed, 30 insertions(+), 146 deletions(-)
---
diff --git a/bse/bseengine.hh b/bse/bseengine.hh
index e141f8f..cd4153e 100644
--- a/bse/bseengine.hh
+++ b/bse/bseengine.hh
@@ -171,7 +171,7 @@ void       bse_transact                 (BseJob               *job,
                                          ...) G_GNUC_NULL_TERMINATED;
 
 /* --- module utilities (EngineThread functions) --- */
-gfloat*    bse_engine_const_values      (gfloat                value);
+float*     bse_engine_const_values      (float value);
 
 /* --- initialization & main loop --- */
 void       bse_engine_constrain         (guint                 latency_ms,
@@ -185,7 +185,7 @@ gboolean   bse_engine_configure         (guint                 latency_ms,
                                          guint                 control_freq);
 
 /* --- miscellaneous --- */
-gfloat*    bse_engine_const_zeros            (guint         smaller_than_BSE_STREAM_MAX_VALUES);
+float*     bse_engine_const_zeros            (uint smaller_than_BSE_STREAM_MAX_VALUES);
 gboolean   bse_engine_has_garbage             (void);
 void       bse_engine_user_thread_collect     (void);
 void       bse_engine_free_ostreams          (guint         n_ostreams,
diff --git a/bse/bseengineutils.cc b/bse/bseengineutils.cc
index ec70f1f..686ae7f 100644
--- a/bse/bseengineutils.cc
+++ b/bse/bseengineutils.cc
@@ -5,6 +5,7 @@
 #include "bseenginenode.hh"
 #include "bseengineschedule.hh"
 #include "bsemathsignal.hh"
+#include <unordered_map>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -642,157 +643,41 @@ _engine_mnl_node_changed (EngineNode *node)
 
 
 /* --- const value blocks --- */
-float*
-bse_engine_const_zeros (guint smaller_than_BSE_STREAM_MAX_VALUES)
-{
-  static const float engine_const_zero_block[BSE_STREAM_MAX_VALUES + 16 /* SIMD alignment */] = { 0, };
-  /* this function is callable from any thread */
-  assert (smaller_than_BSE_STREAM_MAX_VALUES <= BSE_STREAM_MAX_VALUES);
-  return (float*) engine_const_zero_block;
-}
-
-typedef struct
-{
-  guint    n_nodes;
-  gfloat **nodes;
-  guint8  *nodes_used;
-} ConstValuesArray;
-
-static const guint8 CONST_VALUES_EXPIRE = 16;           /* expire value after being unused for 16 times */
+typedef std::unordered_map<float, const float*> FloatBlockMap;
+static std::mutex    engine_const_value_mutex;
+static FloatBlockMap engine_const_value_map;
+static const float   engine_const_values_0[BSE_STREAM_MAX_VALUES + 16] = { 0 }; // 0.0...
 
-static inline gfloat**
-const_values_lookup_nextmost (ConstValuesArray *array,
-                             gfloat            key_value)
+float*
+bse_engine_const_values (float value)
 {
-  guint n_nodes = array->n_nodes;
-
-  if (n_nodes > 0)
+  if (value == 0.0)
+    return const_cast<float*> (engine_const_values_0);
+  std::lock_guard<std::mutex> guard (engine_const_value_mutex);
+  const float *&block = engine_const_value_map[value];
+  if (block == NULL)
     {
-      gfloat **nodes = array->nodes;
-      gfloat **check;
-
-      nodes -= 1;
-      do
-       {
-         guint i;
-         register gfloat cmp;
-
-         i = (n_nodes + 1) >> 1;
-         check = nodes + i;
-         cmp = key_value - **check;
-         if (cmp > BSE_SIGNAL_EPSILON)
-           {
-             n_nodes -= i;
-             nodes = check;
-           }
-         else if (cmp < -BSE_SIGNAL_EPSILON)
-           n_nodes = i - 1;
-         else /* cmp ~==~ 0.0 */
-           return check;   /* matched */
-       }
-      while (n_nodes);
-
-      return check;  /* nextmost */
+      float *value_block = new float[BSE_STREAM_MAX_VALUES + 16];
+      bse_block_fill_float (BSE_STREAM_MAX_VALUES + 16, value_block, value);
+      block = value_block;
     }
-
-  return NULL;
-}
-
-static inline guint
-upper_power2 (guint number)
-{
-  return sfi_alloc_upper_power2 (MAX (number, 8));
+  return const_cast<float*> (block);
 }
 
-static inline void
-const_values_insert (ConstValuesArray *array,
-                    guint             index,
-                    gfloat           *value_block)
-{
-  if (array->n_nodes == 0)
-    {
-      uint new_size = upper_power2 (sizeof (float*));
-      array->nodes = (float**) g_realloc (array->nodes, new_size);
-      array->nodes_used = (guint8*) g_realloc (array->nodes_used, new_size / sizeof (gfloat*));
-      array->n_nodes = 1;
-      assert (index == 0);
-    }
-  else
-    {
-      uint n_nodes = array->n_nodes++;
-      if (*array->nodes[index] < *value_block)
-       index++;
-      if (1)
-       {
-         uint new_size = upper_power2 (array->n_nodes * sizeof (gfloat*));
-         uint old_size = upper_power2 (n_nodes * sizeof (gfloat*));
-         if (new_size != old_size)
-           {
-             array->nodes = (float**) g_realloc (array->nodes, new_size);
-             array->nodes_used = (guint8*) g_realloc (array->nodes_used, new_size / sizeof (float*));
-           }
-       }
-      memmove (array->nodes + index + 1, array->nodes + index, (n_nodes - index) * sizeof (array->nodes[0]));
-      memmove (array->nodes_used + index + 1, array->nodes_used + index, (n_nodes - index) * sizeof 
(array->nodes_used[0]));
-    }
-  array->nodes[index] = value_block;
-  array->nodes_used[index] = CONST_VALUES_EXPIRE;
-}
-
-static ConstValuesArray cvalue_array = { 0, NULL, NULL };
-
 float*
-bse_engine_const_values (gfloat value)
+bse_engine_const_zeros (uint smaller_than_BSE_STREAM_MAX_VALUES)
 {
-  if (fabs (value) < BSE_SIGNAL_EPSILON)
-    return bse_engine_const_zeros (BSE_STREAM_MAX_VALUES);
-
-  float **block = const_values_lookup_nextmost (&cvalue_array, value);
-  /* found correct match? */
-  if (block && fabs (**block - value) < BSE_SIGNAL_EPSILON)
-    {
-      cvalue_array.nodes_used[block - cvalue_array.nodes] = CONST_VALUES_EXPIRE;
-      return *block;
-    }
-  else
-    {
-      /* create new value block */
-      gfloat *values = g_new (gfloat, bse_engine_block_size ());
-      bse_block_fill_float (bse_engine_block_size(), values, value);
-      if (block)
-       const_values_insert (&cvalue_array, block - cvalue_array.nodes, values);
-      else
-       const_values_insert (&cvalue_array, 0, values);
-
-      return values;
-    }
+  assert_return (smaller_than_BSE_STREAM_MAX_VALUES <= BSE_STREAM_MAX_VALUES, NULL);
+  return const_cast<float*> (engine_const_values_0);
 }
 
 void
-_engine_recycle_const_values (gboolean nuke_all)
-{
-  gfloat **nodes = cvalue_array.nodes;
-  guint8 *used = cvalue_array.nodes_used;
-  guint count = cvalue_array.n_nodes, e = 0, i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (nuke_all)
-        used[i] = 0;
-      else
-        used[i]--;      /* invariant: use counts are never 0 */
-
-      if (used[i] == 0)
-       g_free (nodes[i]);
-      else /* preserve node */
-       {
-         if (e < i)
-           {
-             nodes[e] = nodes[i];
-             used[e] = used[i];
-           }
-         e++;
-       }
-    }
-  cvalue_array.n_nodes = e;
+_engine_recycle_const_values (bool remove_all)
+{
+  if (!remove_all)
+    return;
+  std::lock_guard<std::mutex> guard (engine_const_value_mutex);
+  for (const auto &it : engine_const_value_map)
+    delete[] it.second;
+  engine_const_value_map.clear();
 }
diff --git a/bse/bseengineutils.hh b/bse/bseengineutils.hh
index 45ca043..ed97186 100644
--- a/bse/bseengineutils.hh
+++ b/bse/bseengineutils.hh
@@ -9,12 +9,11 @@ void          _engine_free_trans              (BseTrans      *trans);
 BseOStream*    _engine_alloc_ostreams          (guint          n);
 #if 0  /* bseengine.hh: */
 void            bse_engine_user_thread_collect (void);
-gfloat*                bse_engine_const_values         (gfloat         value);
 #endif
 
 
 /* --- MasterThread --- */
-void           _engine_recycle_const_values    (gboolean        nuke_all);
+void           _engine_recycle_const_values    (bool remove_all);
 void           _engine_node_collect_jobs       (EngineNode     *node);
 /* master node list */
 void           _engine_mnl_remove              (EngineNode     *node);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]