diff options
author | Petr Kulhavy <brain@jikos.cz> | 2016-10-14 22:31:41 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2016-11-01 20:02:14 +0200 |
commit | ca7e31f80d8b801e95ce019a14f773728c1acca8 (patch) | |
tree | 7053e9bdbf2eb688e9bc9212136716ef9b1207bf /gst/audioconvert | |
parent | 1820c18b0f0005b117282b2d16c33ef984e91a9b (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
Diffstat (limited to 'gst/audioconvert')
-rw-r--r-- | gst/audioconvert/gstaudioconvert.c | 44 |
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 |