summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Kulhavy <brain@jikos.cz>2016-10-14 22:31:41 +0200
committerSebastian Dröge <sebastian@centricular.com>2016-11-01 20:02:14 +0200
commitca7e31f80d8b801e95ce019a14f773728c1acca8 (patch)
tree7053e9bdbf2eb688e9bc9212136716ef9b1207bf
parent1820c18b0f0005b117282b2d16c33ef984e91a9b (diff)
audioconvert: optimize mask calculation
find_suitable_mask() had complexity O(n^2) on the number of bits. For common case like 2-channel audio the mask was calculated in about 4k loop cycles. Optimize both n_bits_set() and find_suitable_mask() to O(n) where n is the number of bits set in the mask. https://bugzilla.gnome.org/show_bug.cgi?id=772864
-rw-r--r--gst/audioconvert/gstaudioconvert.c44
1 files changed, 22 insertions, 22 deletions
diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c
index d320af480..cdc7778c7 100644
--- a/gst/audioconvert/gstaudioconvert.c
+++ b/gst/audioconvert/gstaudioconvert.c
@@ -302,41 +302,41 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
return result;
}
+/* Count the number of bits set
+ * Optimized for the common case, assuming that the number of channels
+ * (i.e. bits set) is small
+ */
static gint
n_bits_set (guint64 x)
{
- gint i;
- gint c = 0;
- guint64 y = 1;
-
- for (i = 0; i < 64; i++) {
- if (x & y)
- c++;
- y <<= 1;
- }
+ gint c;
+
+ for (c = 0; x; c++)
+ x &= x - 1;
return c;
}
+/* Reduce the mask to the n_chans lowest set bits
+ *
+ * The algorithm clears the n_chans lowest set bits and subtracts the
+ * result from the original mask to get the desired mask.
+ * It is optimized for the common case where n_chans is a small
+ * number. In the worst case, however, it stops after 64 iterations.
+ */
static guint64
find_suitable_mask (guint64 mask, gint n_chans)
{
- guint64 intersection;
- gint i;
-
- i = 0;
+ guint64 x = mask;
- g_assert (n_bits_set (mask) >= n_chans);
+ for (; x && n_chans; n_chans--)
+ x &= x - 1;
- intersection = mask;
- do {
- intersection = intersection & ((~G_GUINT64_CONSTANT (0)) >> i);
- i++;
- } while (n_bits_set (intersection) > n_chans && i < 64);
+ g_assert (x || n_chans == 0);
+ /* assertion fails if mask contained less bits than n_chans
+ * or n_chans was < 0 */
- if (i < 64)
- return intersection;
- return 0;
+ return mask - x;
}
static void