Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 0/5] SBC encoder optimizations for ARM processors
From: Johan Hedberg @ 2010-07-02 19:04 UTC (permalink / raw)
  To: Siarhei Siamashka; +Cc: linux-bluetooth, Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

Hi Siarhei,

On Fri, Jul 02, 2010, Siarhei Siamashka wrote:
> This patch series adds a bunch of ARM assembly optimizations.
> 
> Now all the functions from 'sbc_primitives.c' got NEON optimized
> variants. As benchmarked with the common A2DP case (44100kHz audio
> with bitpool set to 53, 8 subbands, joint stereo), SBC encoding is
> now approximately 1.6x faster overall when compared to bluez-4.66.
> Some more room for improvement still exists though.
> 
> For ARMv6 processors, only analysis filter has been implemented
> (using dual 16-bit multiply-accumulate instructions). But that's
> the most important optimization and it doubles performance already.
> And older processors such as ARM11 are much slower, so they
> definitely benefit more on a relative scale (Nokia N800/N810 users
> may find this update useful).
> 
> All the optimizations are bitexact. Given the same input, they provide
> the same output as the SBC encoder from the previous bluez versions.
> 
> Patches are also available in the branch 'sbc-arm-optimizations' here:
> git://gitorious.org/system-performance/bluez-sbc.git
> 
> Siarhei Siamashka (5):
>   sbc: ARM NEON optimized joint stereo processing in SBC encoder
>   sbc: ARM NEON optimizations for input permutation in SBC encoder
>   sbc: slightly faster 'sbc_calc_scalefactors_neon'
>   sbc: faster 'sbc_calculate_bits' function
>   sbc: ARMv6 optimized version of analysis filter for SBC encoder
> 
>  Makefile.am                |    3 +-
>  sbc/sbc.c                  |   43 ++-
>  sbc/sbc_primitives.c       |    4 +
>  sbc/sbc_primitives_armv6.c |  299 +++++++++++++++++++++
>  sbc/sbc_primitives_armv6.h |   52 ++++
>  sbc/sbc_primitives_neon.c  |  618 ++++++++++++++++++++++++++++++++++++++++++-
>  6 files changed, 988 insertions(+), 31 deletions(-)
>  create mode 100644 sbc/sbc_primitives_armv6.c
>  create mode 100644 sbc/sbc_primitives_armv6.h

Thanks for these! They've all been pushed upstream now.

Johan

^ permalink raw reply

* Re: Bug with Alias
From: Vinicius Gomes @ 2010-07-02 13:56 UTC (permalink / raw)
  Cc: linux-bluetooth
In-Reply-To: <7.0.1.0.2.20100701152541.031ae7c0@gmx.net>

Hi Peter,

On Thu, Jul 1, 2010 at 10:33 AM, Peter Kornatowski <pkorn@gmx.net> wrote:
> Hello,
>
> I have several headsets of the same model, so I set an Alias for each to
> distinguish them in my own application. But since bluez 4.64 the Alias is
> bugged. Sometimes after a reboot or after a bluez restart when i read out
> the Alias through the dbus api, I get the Name instead. I also tried to read
> it with d-feet or through a dbus-send call (dbus-send --system --print-reply
> --dest=org.bluez /org/bluez/11344/hci0/dev_00_XX_XX_XX_XX_XX
> org.bluez.Device.GetProperties) and also got the Name instead of the Alias.
> But in the aliases file under /var/lib/bluetooth/XX:XX:XX:XX:XX:XX/aliases
> is the correct Alias. The bug seems to have something to do with the commit
> 48a2c31cdbc1f2ac2a2bbadbd505976f84a9eaca
> (http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=48a2c31cdbc1f2ac2a2bbadbd505976f84a9eaca).

Thanks for the bug report.

I suggested a fix[1], waiting for review.

> I hope someone can resolve this issue.
>
> Thanks,
> Peter
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


Cheers,
-- 
Vinicius

[1] http://git.infradead.org/users/vcgomes/bluez.git/commitdiff/d574f1d79edb8be697730e0d1a6bb3534190a6a3

^ permalink raw reply

* [PATCH 5/5] sbc: ARMv6 optimized version of analysis filter for SBC encoder
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

The optimized filter gets enabled when the code is compiled
with -mcpu=/-march options set to target the processors which
support ARMv6 instructions. This code is also disabled when
NEON is used (which is a lot better alternative). For additional
safety ARM EABI is required and thumb mode should not be used.

Benchmarks from ARM11:

== 8 subbands ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m 35.65s
user    0m 34.17s
sys     0m 1.28s

$ time ./sbcenc.armv6 -b53 -s8 -j test.au > /dev/null

real    0m 17.29s
user    0m 15.47s
sys     0m 0.67s

== 4 subbands ==

$ time ./sbcenc -b53 -s4 -j test.au > /dev/null

real    0m 25.28s
user    0m 23.76s
sys     0m 1.32s

$ time ./sbcenc.armv6 -b53 -s4 -j test.au > /dev/null

real    0m 18.64s
user    0m 15.78s
sys     0m 2.22s
---
 Makefile.am                |    3 +-
 sbc/sbc_primitives.c       |    4 +
 sbc/sbc_primitives_armv6.c |  299 ++++++++++++++++++++++++++++++++++++++++++++
 sbc/sbc_primitives_armv6.h |   52 ++++++++
 4 files changed, 357 insertions(+), 1 deletions(-)
 create mode 100644 sbc/sbc_primitives_armv6.c
 create mode 100644 sbc/sbc_primitives_armv6.h

diff --git a/Makefile.am b/Makefile.am
index 36ffde3..9ed3f89 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,7 +65,8 @@ noinst_LTLIBRARIES += sbc/libsbc.la
 sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
 			sbc/sbc_primitives.h sbc/sbc_primitives.c \
 			sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
-			sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c
+			sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
+			sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
 
 sbc_libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
 					-funswitch-loops -funroll-loops
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index c73fb1c..f87fb5a 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -34,6 +34,7 @@
 #include "sbc_primitives.h"
 #include "sbc_primitives_mmx.h"
 #include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
 
 /*
  * A reference C code of analysis filter with SIMD-friendly tables
@@ -540,6 +541,9 @@ void sbc_init_primitives(struct sbc_encoder_state *state)
 #endif
 
 	/* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+	sbc_init_primitives_armv6(state);
+#endif
 #ifdef SBC_BUILD_WITH_NEON_SUPPORT
 	sbc_init_primitives_neon(state);
 #endif
diff --git a/sbc/sbc_primitives_armv6.c b/sbc/sbc_primitives_armv6.c
new file mode 100644
index 0000000..9586098
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.c
@@ -0,0 +1,299 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_armv6.h"
+
+/*
+ * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
+ */
+
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+
+static void __attribute__((naked)) sbc_analyze_four_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	asm volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #32]\n"
+		"ldrd   r6,  r7,  [r2, #32]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #48]\n"
+		"ldrd   r10, r11, [r2, #48]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #40]\n"
+		"ldrd   r10, r11, [r2, #40]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #56]\n"
+		"ldrd   r6,  r7,  [r2, #56]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #80]\n"    /* start loading cos table */
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"ldrd   r8,  r9,  [r2, #96]\n"
+		"ldrd   r10, r11, [r2, #104]\n"   /* cos table fully loaded */
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_four(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_four_armv6)((in), (out), (consts))
+
+static void __attribute__((naked)) sbc_analyze_eight_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	asm volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"ldrd   r8,  r9,  [r0, #56]\n"
+		"ldrd   r10, r11, [r2, #56]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #88]\n"
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #120]\n"
+		"ldrd   r10, r11, [r2, #120]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #152]\n"
+		"ldrd   r6,  r7,  [r2, #152]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[6] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[7] is done */
+		"ldrd   r4,  r5,  [r0, #48]\n"
+		"ldrd   r6,  r7,  [r2, #48]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[6] and t1[7] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r8,  r10, r14\n"
+		"smlad  r12, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #80]\n"
+		"ldrd   r10, r11, [r2, #80]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #112]\n"
+		"ldrd   r6,  r7,  [r2, #112]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #144]\n"
+		"ldrd   r10, r11, [r2, #144]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"smlad  r3,  r8,  r10, r3\n"      /* t1[4] is done */
+		"smlad  r12, r9,  r11, r12\n"     /* t1[5] is done */
+		"ldrd   r8,  r9,  [r0, #32]\n"
+		"ldrd   r10, r11, [r2, #32]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[4] and t1[5] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #96]\n"
+		"ldrd   r10, r11, [r2, #96]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #128]\n"
+		"ldrd   r6,  r7,  [r2, #128]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #40]\n"
+		"ldrd   r6,  r7,  [r2, #40]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #104]\n"
+		"ldrd   r6,  r7,  [r2, #104]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #136]\n"
+		"ldrd   r10, r11, [r2, #136]!\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #(160 - 136 + 0)]\n"
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #(160 - 136 + 8)]\n"
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+						  /* r3  = t2[0:1] */
+						  /* r12 = t2[2:3] */
+		"pop    {r0, r14}\n"              /* t2[4:5], t2[6:7] */
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 32)]\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 0)]\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
+		"stmia  r1!, {r4, r5}\n"
+		"smuad  r4,  r3,  r8\n"
+		"smuad  r5,  r3,  r9\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 32)]\n"
+		"stmia  r1!, {r6, r7}\n"
+		"smuad  r6,  r3,  r10\n"
+		"smuad  r7,  r3,  r11\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1!, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_eight(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_eight_armv6)((in), (out), (consts))
+
+static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
+{
+	state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6;
+	state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6;
+	state->implementation_info = "ARMv6 SIMD";
+}
+
+#endif
diff --git a/sbc/sbc_primitives_armv6.h b/sbc/sbc_primitives_armv6.h
new file mode 100644
index 0000000..1862aed
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.h
@@ -0,0 +1,52 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_ARMV6_H
+#define __SBC_PRIMITIVES_ARMV6_H
+
+#include "sbc_primitives.h"
+
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+	defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+	defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
+	defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
+	defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
+	defined(__ARM_ARCH_7M__)
+#define SBC_HAVE_ARMV6 1
+#endif
+
+#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
+	defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
+	defined(__ARM_EABI__) && !defined(__thumb__) && \
+	!defined(__ARM_NEON__)
+
+#define SBC_BUILD_WITH_ARMV6_SUPPORT
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 4/5] sbc: faster 'sbc_calculate_bits' function
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

By using SBC_ALWAYS_INLINE trick, the implementation of 'sbc_calculate_bits'
function is split into two branches, each having 'subband' variable value
known at compile time. It helps the compiler to generate more optimal code
by saving at least one extra register, and also provides more obvious
opportunities for loops unrolling.

Benchmarked on ARM Cortex-A8:

== Before: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m3.989s
user    0m3.602s
sys     0m0.391s

samples  %        image name               symbol name
26057    32.6128  sbcenc                   sbc_pack_frame
20003    25.0357  sbcenc                   sbc_analyze_4b_8s_neon
14220    17.7977  sbcenc                   sbc_calculate_bits
8498     10.6361  no-vmlinux               /no-vmlinux
5300      6.6335  sbcenc                   sbc_calc_scalefactors_j_neon
3235      4.0489  sbcenc                   sbc_enc_process_input_8s_be_neon
2172      2.7185  sbcenc                   sbc_encode

== After: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m3.652s
user    0m3.195s
sys     0m0.445s

samples  %        image name               symbol name
26207    36.0095  sbcenc                   sbc_pack_frame
19820    27.2335  sbcenc                   sbc_analyze_4b_8s_neon
8629     11.8566  no-vmlinux               /no-vmlinux
6988      9.6018  sbcenc                   sbc_calculate_bits
5094      6.9994  sbcenc                   sbc_calc_scalefactors_j_neon
3351      4.6044  sbcenc                   sbc_enc_process_input_8s_be_neon
2182      2.9982  sbcenc                   sbc_encode
---
 sbc/sbc.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/sbc/sbc.c b/sbc/sbc.c
index 1921585..a6391ae 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -160,7 +160,8 @@ static uint8_t sbc_crc8(const uint8_t *data, size_t len)
  * Takes a pointer to the frame in question, a pointer to the bits array and
  * the sampling frequency (as 2 bit integer)
  */
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+		const struct sbc_frame *frame, int (*bits)[8], int subbands)
 {
 	uint8_t sf = frame->frequency;
 
@@ -171,17 +172,17 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 		for (ch = 0; ch < frame->channels; ch++) {
 			max_bitneed = 0;
 			if (frame->allocation == SNR) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					bitneed[ch][sb] = frame->scale_factor[ch][sb];
 					if (bitneed[ch][sb] > max_bitneed)
 						max_bitneed = bitneed[ch][sb];
 				}
 			} else {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if (frame->scale_factor[ch][sb] == 0)
 						bitneed[ch][sb] = -5;
 					else {
-						if (frame->subbands == 4)
+						if (subbands == 4)
 							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
 						else
 							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -202,7 +203,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 				bitslice--;
 				bitcount += slicecount;
 				slicecount = 0;
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
 						slicecount++;
 					else if (bitneed[ch][sb] == bitslice + 1)
@@ -215,7 +216,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 				bitslice--;
 			}
 
-			for (sb = 0; sb < frame->subbands; sb++) {
+			for (sb = 0; sb < subbands; sb++) {
 				if (bitneed[ch][sb] < bitslice + 2)
 					bits[ch][sb] = 0;
 				else {
@@ -225,7 +226,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 				}
 			}
 
-			for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
 				if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
 					bits[ch][sb]++;
 					bitcount++;
@@ -235,7 +237,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 				}
 			}
 
-			for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
 				if (bits[ch][sb] < 16) {
 					bits[ch][sb]++;
 					bitcount++;
@@ -251,7 +254,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 		max_bitneed = 0;
 		if (frame->allocation == SNR) {
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					bitneed[ch][sb] = frame->scale_factor[ch][sb];
 					if (bitneed[ch][sb] > max_bitneed)
 						max_bitneed = bitneed[ch][sb];
@@ -259,11 +262,11 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 			}
 		} else {
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if (frame->scale_factor[ch][sb] == 0)
 						bitneed[ch][sb] = -5;
 					else {
-						if (frame->subbands == 4)
+						if (subbands == 4)
 							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
 						else
 							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -286,7 +289,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 			bitcount += slicecount;
 			slicecount = 0;
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
 						slicecount++;
 					else if (bitneed[ch][sb] == bitslice + 1)
@@ -301,7 +304,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 		}
 
 		for (ch = 0; ch < 2; ch++) {
-			for (sb = 0; sb < frame->subbands; sb++) {
+			for (sb = 0; sb < subbands; sb++) {
 				if (bitneed[ch][sb] < bitslice + 2) {
 					bits[ch][sb] = 0;
 				} else {
@@ -325,7 +328,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -340,7 +344,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -349,6 +354,14 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
 
 }
 
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+	if (frame->subbands == 4)
+		sbc_calculate_bits_internal(frame, bits, 4);
+	else
+		sbc_calculate_bits_internal(frame, bits, 8);
+}
+
 /*
  * Unpacks a SBC frame at the beginning of the stream in data,
  * which has at most len bytes into frame.
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 3/5] sbc: slightly faster 'sbc_calc_scalefactors_neon'
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

Previous variant was basically derived from C and MMX implementations.
Now new variant makes use of 'vmax' instruction, which is available in
NEON and can do this job faster. The same method for calculating scale
factors is also used in 'sbc_calc_scalefactors_j_neon'.

Benchmarked without joint stereo on ARM Cortex-A8:

== Before: ==

$ time ./sbcenc -b53 -s8 test.au > /dev/null

real    0m3.851s
user    0m3.375s
sys     0m0.469s

samples  %        image name               symbol name
26260    34.2672  sbcenc                   sbc_pack_frame
20013    26.1154  sbcenc                   sbc_analyze_4b_8s_neon
13796    18.0027  sbcenc                   sbc_calculate_bits
8388     10.9457  no-vmlinux               /no-vmlinux
3229      4.2136  sbcenc                   sbc_enc_process_input_8s_be_neon
2408      3.1422  sbcenc                   sbc_calc_scalefactors_neon
2093      2.7312  sbcenc                   sbc_encode

== After: ==

$ time ./sbcenc -b53 -s8 test.au > /dev/null

real    0m3.796s
user    0m3.344s
sys     0m0.438s

samples  %        image name               symbol name
26582    34.8726  sbcenc                   sbc_pack_frame
20032    26.2797  sbcenc                   sbc_analyze_4b_8s_neon
13808    18.1146  sbcenc                   sbc_calculate_bits
8374     10.9858  no-vmlinux               /no-vmlinux
3187      4.1810  sbcenc                   sbc_enc_process_input_8s_be_neon
2027      2.6592  sbcenc                   sbc_encode
1766      2.3168  sbcenc                   sbc_calc_scalefactors_neon
---
 sbc/sbc_primitives_neon.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
index 7713759..0572158 100644
--- a/sbc/sbc_primitives_neon.c
+++ b/sbc/sbc_primitives_neon.c
@@ -248,8 +248,11 @@ static void sbc_calc_scalefactors_neon(
 			int blk = blocks;
 			int32_t *in = &sb_sample_f[0][ch][sb];
 			asm volatile (
-				"vmov.s32  q0, %[c1]\n"
+				"vmov.s32  q0, #0\n"
 				"vmov.s32  q1, %[c1]\n"
+				"vmov.s32  q14, #1\n"
+				"vmov.s32  q15, %[c2]\n"
+				"vadd.s32  q1, q1, q14\n"
 			"1:\n"
 				"vld1.32   {d16, d17}, [%[in], :128], %[inc]\n"
 				"vabs.s32  q8,  q8\n"
@@ -259,22 +262,14 @@ static void sbc_calc_scalefactors_neon(
 				"vabs.s32  q10, q10\n"
 				"vld1.32   {d22, d23}, [%[in], :128], %[inc]\n"
 				"vabs.s32  q11, q11\n"
-				"vcgt.s32  q12, q8,  #0\n"
-				"vcgt.s32  q13, q9,  #0\n"
-				"vcgt.s32  q14, q10, #0\n"
-				"vcgt.s32  q15, q11, #0\n"
-				"vadd.s32  q8,  q8,  q12\n"
-				"vadd.s32  q9,  q9,  q13\n"
-				"vadd.s32  q10, q10, q14\n"
-				"vadd.s32  q11, q11, q15\n"
-				"vorr.s32  q0,  q0,  q8\n"
-				"vorr.s32  q1,  q1,  q9\n"
-				"vorr.s32  q0,  q0,  q10\n"
-				"vorr.s32  q1,  q1,  q11\n"
+				"vmax.s32  q0,  q0,  q8\n"
+				"vmax.s32  q1,  q1,  q9\n"
+				"vmax.s32  q0,  q0,  q10\n"
+				"vmax.s32  q1,  q1,  q11\n"
 				"subs      %[blk], %[blk], #4\n"
 				"bgt       1b\n"
-				"vorr.s32  q0,  q0, q1\n"
-				"vmov.s32  q15, %[c2]\n"
+				"vmax.s32  q0,  q0,  q1\n"
+				"vsub.s32  q0,  q0,  q14\n"
 				"vclz.s32  q0,  q0\n"
 				"vsub.s32  q0,  q15, q0\n"
 				"vst1.32   {d0, d1}, [%[out], :128]\n"
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 2/5] sbc: ARM NEON optimizations for input permutation in SBC encoder
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

Using SIMD optimizations for 'sbc_enc_process_input_*' functions provides
a modest, but consistent speedup in all SBC encoding cases.

Benchmarked on ARM Cortex-A8:

== Before: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m4.389s
user    0m3.969s
sys     0m0.422s

samples  %        image name               symbol name
26234    29.9625  sbcenc                   sbc_pack_frame
20057    22.9076  sbcenc                   sbc_analyze_4b_8s_neon
14306    16.3393  sbcenc                   sbc_calculate_bits
9866     11.2682  sbcenc                   sbc_enc_process_input_8s_be
8506      9.7149  no-vmlinux               /no-vmlinux
5219      5.9608  sbcenc                   sbc_calc_scalefactors_j_neon
2280      2.6040  sbcenc                   sbc_encode
661       0.7549  libc-2.10.1.so           memcpy

== After: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m3.989s
user    0m3.602s
sys     0m0.391s

samples  %        image name               symbol name
26057    32.6128  sbcenc                   sbc_pack_frame
20003    25.0357  sbcenc                   sbc_analyze_4b_8s_neon
14220    17.7977  sbcenc                   sbc_calculate_bits
8498     10.6361  no-vmlinux               /no-vmlinux
5300      6.6335  sbcenc                   sbc_calc_scalefactors_j_neon
3235      4.0489  sbcenc                   sbc_enc_process_input_8s_be_neon
2172      2.7185  sbcenc                   sbc_encode
---
 sbc/sbc_primitives_neon.c |  350 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 350 insertions(+), 0 deletions(-)

diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
index c6a16ac..7713759 100644
--- a/sbc/sbc_primitives_neon.c
+++ b/sbc/sbc_primitives_neon.c
@@ -536,12 +536,362 @@ int sbc_calc_scalefactors_j_neon(
 	return joint;
 }
 
+#define PERM_BE(a, b, c, d) {             \
+		(a * 2) + 1, (a * 2) + 0, \
+		(b * 2) + 1, (b * 2) + 0, \
+		(c * 2) + 1, (c * 2) + 0, \
+		(d * 2) + 1, (d * 2) + 0  \
+	}
+#define PERM_LE(a, b, c, d) {             \
+		(a * 2) + 0, (a * 2) + 1, \
+		(b * 2) + 0, (b * 2) + 1, \
+		(c * 2) + 0, (c * 2) + 1, \
+		(d * 2) + 0, (d * 2) + 1  \
+	}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[2][8] = {
+		PERM_BE(7, 3, 6, 4),
+		PERM_BE(0, 2, 1, 5)
+	};
+	static SBC_ALIGNED uint8_t perm_le[2][8] = {
+		PERM_LE(7, 3, 6, 4),
+		PERM_LE(0, 2, 1, 5)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+		int16_t *src = &X[0][position];
+		asm volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0}, [%[src], :64]!\n"
+			"vst1.16 {d0}, [%[dst], :64]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+			src = &X[1][position];
+			asm volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0}, [%[src], :64]!\n"
+				"vst1.16 {d0}, [%[dst], :64]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 40;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vuzp.16 d4,  d5\n"
+			"vld1.8  {d20, d21}, [%[pcm]]!\n"
+			"vuzp.16 d20, d21\n"
+			"vswp    d5,  d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld2.16 {d4, d5}, [%[pcm]]!\n"
+			"vld2.16 {d20, d21}, [%[pcm]]!\n"
+			"vswp    d5, d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[4][8] = {
+		PERM_BE(15, 7, 14, 8),
+		PERM_BE(13, 9, 12, 10),
+		PERM_BE(11, 3, 6,  0),
+		PERM_BE(5,  1, 4,  2)
+	};
+	static SBC_ALIGNED uint8_t perm_le[4][8] = {
+		PERM_LE(15, 7, 14, 8),
+		PERM_LE(13, 9, 12, 10),
+		PERM_LE(11, 3, 6,  0),
+		PERM_LE(5,  1, 4,  2)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+		int16_t *src = &X[0][position];
+		asm volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+			src = &X[1][position];
+			asm volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 72;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vuzp.16 q2,  q3\n"
+			"vld1.8  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vuzp.16 q10, q11\n"
+			"vswp    q3,  q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld2.16  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vld2.16  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vswp    q3, q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
 void sbc_init_primitives_neon(struct sbc_encoder_state *state)
 {
 	state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
 	state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
 	state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
 	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+	state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+	state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+	state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+	state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
 	state->implementation_info = "NEON";
 }
 
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 1/5] sbc: ARM NEON optimized joint stereo processing in SBC encoder
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka
In-Reply-To: <1278073542-14859-1-git-send-email-siarhei.siamashka@gmail.com>

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

Improves SBC encoding performance when joint stereo is used, which
is a typical A2DP configuration.

Benchmarked on ARM Cortex-A8:

== Before: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m5.239s
user    0m4.805s
sys     0m0.430s

samples  %        image name               symbol name
26083    25.0856  sbcenc                   sbc_pack_frame
21548    20.7240  sbcenc                   sbc_calc_scalefactors_j
19910    19.1486  sbcenc                   sbc_analyze_4b_8s_neon
14377    13.8272  sbcenc                   sbc_calculate_bits
9990      9.6080  sbcenc                   sbc_enc_process_input_8s_be
8667      8.3356  no-vmlinux               /no-vmlinux
2263      2.1765  sbcenc                   sbc_encode
696       0.6694  libc-2.10.1.so           memcpy

== After: ==

$ time ./sbcenc -b53 -s8 -j test.au > /dev/null

real    0m4.389s
user    0m3.969s
sys     0m0.422s

samples  %        image name               symbol name
26234    29.9625  sbcenc                   sbc_pack_frame
20057    22.9076  sbcenc                   sbc_analyze_4b_8s_neon
14306    16.3393  sbcenc                   sbc_calculate_bits
9866     11.2682  sbcenc                   sbc_enc_process_input_8s_be
8506      9.7149  no-vmlinux               /no-vmlinux
5219      5.9608  sbcenc                   sbc_calc_scalefactors_j_neon
2280      2.6040  sbcenc                   sbc_encode
661       0.7549  libc-2.10.1.so           memcpy
---
 sbc/sbc_primitives_neon.c |  243 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 insertions(+), 0 deletions(-)

diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
index 2a4cdf0..c6a16ac 100644
--- a/sbc/sbc_primitives_neon.c
+++ b/sbc/sbc_primitives_neon.c
@@ -294,11 +294,254 @@ static void sbc_calc_scalefactors_neon(
 	}
 }
 
+int sbc_calc_scalefactors_j_neon(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int subbands)
+{
+	static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+		8,   4,  2,  1, 128, 64, 32, 16
+	};
+	int joint, i;
+	int32_t  *in0, *in1;
+	int32_t  *in = &sb_sample_f[0][0][0];
+	uint32_t *out0, *out1;
+	uint32_t *out = &scale_factor[0][0];
+	int32_t  *consts = joint_bits_mask;
+
+	i = subbands;
+
+	asm volatile (
+		/*
+		 * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+		 * input:     q0  = ((1 << SCALE_OUT_BITS) + 1)
+		 *            %[in0] - samples for channel 0
+		 *            %[in1] - samples for shannel 1
+		 * output:    q0, q1 - scale factors without joint stereo
+		 *            q2, q3 - scale factors with joint stereo
+		 *            q15    - joint stereo selection mask
+		 */
+		".macro calc_scalefactors\n"
+			"vmov.s32  q1, q0\n"
+			"vmov.s32  q2, q0\n"
+			"vmov.s32  q3, q0\n"
+			"mov       %[i], %[blocks]\n"
+		"1:\n"
+			"vld1.32   {d18, d19}, [%[in1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128], %[inc]\n"
+			"vhadd.s32 q10, q8,  q11\n"
+			"vhsub.s32 q11, q8,  q11\n"
+			"vabs.s32  q8,  q8\n"
+			"vabs.s32  q9,  q9\n"
+			"vabs.s32  q10, q10\n"
+			"vabs.s32  q11, q11\n"
+			"vmax.s32  q0,  q0,  q8\n"
+			"vmax.s32  q1,  q1,  q9\n"
+			"vmax.s32  q2,  q2,  q10\n"
+			"vmax.s32  q3,  q3,  q11\n"
+			"subs      %[i], %[i], #1\n"
+			"bgt       1b\n"
+			"vsub.s32  q0,  q0,  q14\n"
+			"vsub.s32  q1,  q1,  q14\n"
+			"vsub.s32  q2,  q2,  q14\n"
+			"vsub.s32  q3,  q3,  q14\n"
+			"vclz.s32  q0,  q0\n"
+			"vclz.s32  q1,  q1\n"
+			"vclz.s32  q2,  q2\n"
+			"vclz.s32  q3,  q3\n"
+			"vsub.s32  q0,  q13, q0\n"
+			"vsub.s32  q1,  q13, q1\n"
+			"vsub.s32  q2,  q13, q2\n"
+			"vsub.s32  q3,  q13, q3\n"
+		".endm\n"
+		/*
+		 * constants: q14 = 1
+		 * input: q15    - joint stereo selection mask
+		 *        %[in0] - value set by calc_scalefactors macro
+		 *        %[in1] - value set by calc_scalefactors macro
+		 */
+		".macro update_joint_stereo_samples\n"
+			"sub       %[out1], %[in1], %[inc]\n"
+			"sub       %[out0], %[in0], %[inc]\n"
+			"sub       %[in1], %[in1], %[inc], asl #1\n"
+			"sub       %[in0], %[in0], %[inc], asl #1\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"sub       %[inc], %[zero], %[inc], asl #1\n"
+			"sub       %[i], %[blocks], #2\n"
+		"2:\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128], %[inc]\n"
+			"vbif.s32  d4,  d2,  d30\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbif.s32  d5,  d3,  d31\n"
+			"vst1.32   {d22, d23}, [%[in0], :128], %[inc]\n"
+			"vbif.s32  d6,  d0,  d30\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vbif.s32  d7,  d1,  d31\n"
+			"vst1.32   {d4, d5}, [%[out1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128], %[inc]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"subs      %[i], %[i], #2\n"
+			"bgt       2b\n"
+			"sub       %[inc], %[zero], %[inc], asr #1\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128]\n"
+			"vbif.s32  q2,  q1,  q15\n"
+			"vst1.32   {d22, d23}, [%[in0], :128]\n"
+			"vbif.s32  q3,  q0,  q15\n"
+			"vst1.32   {d4, d5}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128]\n"
+		".endm\n"
+
+		"vmov.s32  q14, #1\n"
+		"vmov.s32  q13, %[c2]\n"
+
+		"cmp   %[i], #4\n"
+		"bne   8f\n"
+
+	"4:\n" /* 4 subbands */
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n" /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate and save to memory 'joint' variable */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+		"b     9f\n"
+
+	"8:\n" /* 8 subbands */
+		"add   %[in0], %[in], #16\n\n"
+		"add   %[in1], %[in], #48\n"
+		"add   %[out0], %[out], #16\n\n"
+		"add   %[out1], %[out], #48\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 4, 5, 6 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n"  /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate part of 'joint' variable and save it to d24 */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vpadd.s32 d24, d16, d16\n"
+
+		"update_joint_stereo_samples\n"
+
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* combine last part of 'joint' with d24 and save to memory */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"  vadd.s32  d16, d16, d24\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+	"9:\n"
+		".purgem calc_scalefactors\n"
+		".purgem update_joint_stereo_samples\n"
+		:
+		  [i]      "+&r" (i),
+		  [in]     "+&r" (in),
+		  [in0]    "=&r" (in0),
+		  [in1]    "=&r" (in1),
+		  [out]    "+&r" (out),
+		  [out0]   "=&r" (out0),
+		  [out1]   "=&r" (out1),
+		  [consts] "+&r" (consts)
+		:
+		  [inc]      "r" ((char *) &sb_sample_f[1][0][0] -
+				 (char *) &sb_sample_f[0][0][0]),
+		  [blocks]   "r" (blocks),
+		  [joint]    "r" (&joint),
+		  [c1]       "i" (1 << SCALE_OUT_BITS),
+		  [c2]       "i" (31 - SCALE_OUT_BITS),
+		  [zero]     "r" (0)
+		: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+		  "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+		  "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+		  "d30", "d31", "cc", "memory");
+
+	return joint;
+}
+
 void sbc_init_primitives_neon(struct sbc_encoder_state *state)
 {
 	state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
 	state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
 	state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
 	state->implementation_info = "NEON";
 }
 
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 0/5] SBC encoder optimizations for ARM processors
From: Siarhei Siamashka @ 2010-07-02 12:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Siarhei Siamashka

From: Siarhei Siamashka <siarhei.siamashka@nokia.com>

This patch series adds a bunch of ARM assembly optimizations.

Now all the functions from 'sbc_primitives.c' got NEON optimized
variants. As benchmarked with the common A2DP case (44100kHz audio
with bitpool set to 53, 8 subbands, joint stereo), SBC encoding is
now approximately 1.6x faster overall when compared to bluez-4.66.
Some more room for improvement still exists though.

For ARMv6 processors, only analysis filter has been implemented
(using dual 16-bit multiply-accumulate instructions). But that's
the most important optimization and it doubles performance already.
And older processors such as ARM11 are much slower, so they
definitely benefit more on a relative scale (Nokia N800/N810 users
may find this update useful).

All the optimizations are bitexact. Given the same input, they provide
the same output as the SBC encoder from the previous bluez versions.

Patches are also available in the branch 'sbc-arm-optimizations' here:
git://gitorious.org/system-performance/bluez-sbc.git

Siarhei Siamashka (5):
  sbc: ARM NEON optimized joint stereo processing in SBC encoder
  sbc: ARM NEON optimizations for input permutation in SBC encoder
  sbc: slightly faster 'sbc_calc_scalefactors_neon'
  sbc: faster 'sbc_calculate_bits' function
  sbc: ARMv6 optimized version of analysis filter for SBC encoder

 Makefile.am                |    3 +-
 sbc/sbc.c                  |   43 ++-
 sbc/sbc_primitives.c       |    4 +
 sbc/sbc_primitives_armv6.c |  299 +++++++++++++++++++++
 sbc/sbc_primitives_armv6.h |   52 ++++
 sbc/sbc_primitives_neon.c  |  618 ++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 988 insertions(+), 31 deletions(-)
 create mode 100644 sbc/sbc_primitives_armv6.c
 create mode 100644 sbc/sbc_primitives_armv6.h


^ permalink raw reply

* Re: [PATCH] drivers: bluetooth: bluecard_cs.c: Fixed include error, changed to linux/io.h
From: David Miller @ 2010-07-02  4:28 UTC (permalink / raw)
  To: gustavo; +Cc: codyrester, marcel, linux-bluetooth, linux-kernel
In-Reply-To: <20100627065006.GA32318@vigoh>

From: "Gustavo F. Padovan" <gustavo@padovan.org>
Date: Sun, 27 Jun 2010 03:50:07 -0300

> * Cody Rester <codyrester@gmail.com> [2010-06-27 02:12:22 -0400]:
> 
>> Fixed include error, changed to linux/io.h
>> 
>> Signed-off-by: Cody Rester <codyrester@gmail.com>
...
> Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>

Applied, thanks.

^ permalink raw reply

* Bug with Alias
From: Peter Kornatowski @ 2010-07-01 13:33 UTC (permalink / raw)
  To: linux-bluetooth

Hello,

I have several headsets of the same model, so I set an Alias for each 
to distinguish them in my own application. But since bluez 4.64 the 
Alias is bugged. Sometimes after a reboot or after a bluez restart 
when i read out the Alias through the dbus api, I get the Name 
instead. I also tried to read it with d-feet or through a dbus-send 
call (dbus-send --system --print-reply --dest=org.bluez 
/org/bluez/11344/hci0/dev_00_XX_XX_XX_XX_XX 
org.bluez.Device.GetProperties) and also got the Name instead of the 
Alias. But in the aliases file under 
/var/lib/bluetooth/XX:XX:XX:XX:XX:XX/aliases is the correct Alias. 
The bug seems to have something to do with the commit 
48a2c31cdbc1f2ac2a2bbadbd505976f84a9eaca 
(http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=48a2c31cdbc1f2ac2a2bbadbd505976f84a9eaca).
I hope someone can resolve this issue.

Thanks,
Peter


^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix abuse of the preincrement operator
From: David Miller @ 2010-06-30 20:10 UTC (permalink / raw)
  To: gustavo; +Cc: dhowells, linux-bluetooth, justinmattock, linux-kernel
In-Reply-To: <20100628131058.GA25275@vigoh>

From: "Gustavo F. Padovan" <gustavo@padovan.org>
Date: Mon, 28 Jun 2010 10:12:30 -0300

> Hi David,
> 
> * David Howells <dhowells@redhat.com> [2010-06-28 13:57:52 +0100]:
> 
>> Fix abuse of the preincrement operator as detected when building with gcc
>> 4.6.0:
>> 
>> 	 CC [M]  drivers/bluetooth/hci_bcsp.o
>> 	drivers/bluetooth/hci_bcsp.c: In function 'bcsp_prepare_pkt':
>> 	drivers/bluetooth/hci_bcsp.c:247:20: warning: operation on 'bcsp->msgq_txseq' may be undefined
>> 
>> Reported-by: Justin P. Mattock <justinmattock@gmail.com>
>> Signed-off-by: David Howells <dhowells@redhat.com>
...
> Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>

Applied, thanks everyone.

^ permalink raw reply

* Re: [PATCH] Add udev scripts to gitignore.
From: Johan Hedberg @ 2010-06-30 18:54 UTC (permalink / raw)
  To: João Paulo Rechi Vita; +Cc: linux-bluetooth
In-Reply-To: <AANLkTinBR8gOf-jsqxf2gUkAm08gprUe_KsGc4p7rxLU@mail.gmail.com>

On Wed, Jun 30, 2010, João Paulo Rechi Vita wrote:
> 2010/6/30 Johan Hedberg <johan.hedberg@gmail.com>:
> > Hi,
> >
> > On Tue, Jun 29, 2010, João Paulo Rechi Vita wrote:
> >> +scripts/97-bluetooth.rules
> >> +scripts/97-bluetooth-hid2hci.rules
> >
> > How do these files get created? I've never seen them in my bluez tree.
> >
> 
> You have to enable udevrules during the configure phase. They were
> probably leftover because most devs use bootstrap-configure script,
> which pass --disable-udevrules to configure.

Ok, I now get them with that switch. The patch is now pushed upstream
with a minor modification of grouping the entries together with
scripts/bluetooth.rules (which was already in .gitignore).

Johan

^ permalink raw reply

* Re: [PATCH 2/2] Added support for updating EIR whenever record is added or removed
From: ingas @ 2010-06-30 16:19 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20100630082956.GA25928@jh-x301>

Hi Johan,

Thank you for your comprehensive comments. I will incorporate your
suggestions and investigate the feasibility of splitting the patch into
smaller functional pieces.

Inga

> Hi Inga,
>
> On Thu, Jun 17, 2010, Inga Stotland wrote:
>> ---
>>  plugins/service.c  |   18 ++++++
>>  src/adapter.c      |  148
>> ++++++++++++++++++++++++++++++++++++++++++++++++++--
>>  src/adapter.h      |    5 +-
>>  src/dbus-hci.c     |    6 +-
>>  src/sdpd-service.c |  106 +++++++++++++++++++++++++++++++------
>>  src/sdpd.h         |   20 +++++++
>>  6 files changed, 277 insertions(+), 26 deletions(-)
>
> Could you please split this patch up into smaller chunks if possible. It
> seems it has several parts which could be considered logically
> independent.
>
> Some other comments:
>
>>  void adapter_set_class_complete(bdaddr_t *bdaddr, uint8_t status)
>>  {
>>  	uint8_t class[3];
>> @@ -2677,6 +2698,7 @@ static void append_dict_valist(DBusMessageIter
>> *iter,
>>  	DBusMessageIter dict;
>>  	const char *key;
>>  	int type;
>> +	int n_elements;
>>  	void *val;
>>
>>  	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
>> @@ -2688,7 +2710,12 @@ static void append_dict_valist(DBusMessageIter
>> *iter,
>>  	while (key) {
>>  		type = va_arg(var_args, int);
>>  		val = va_arg(var_args, void *);
>> -		dict_append_entry(&dict, key, type, val);
>> +		if (type == DBUS_TYPE_ARRAY) {
>> +			n_elements = va_arg(var_args, int);
>> +			if (n_elements > 0)
>> +				dict_append_array(&dict, key, DBUS_TYPE_STRING, val, n_elements);
>> +		} else
>> +			dict_append_entry(&dict, key, type, val);
>>  		key = va_arg(var_args, char *);
>>  	}
>>
>
> It looks like this at least could be a separate patch (DBUS_TYPE_ARRAY
> support for append_dict_valist).
>
>> @@ -2719,8 +2746,106 @@ static void emit_device_found(const char *path,
>> const char *address,
>>  	g_dbus_send_message(connection, signal);
>>  }
>>
>> +
>> +static int get_uuid_count_eir (uint8_t *eir_data)
>
> Why the extra empty line? In general there should never be a need for
> two consecutive empty lines.
>
>> +{
>> +	uint8_t type;
>> +	uint8_t len = 0;
>> +	uint8_t field_len;
>> +	int count = 0;
>> +
>> +	while (len < EIR_DATA_LENGTH) {
>> +		type = eir_data[1];
>> +		field_len = eir_data[0];
>> +		if ((type == EIR_UUID16_SOME) || (type == EIR_UUID16_ALL))
>> +			count += field_len/2;
>> +		else if ((type == EIR_UUID32_SOME) || (type == EIR_UUID32_ALL))
>> +			count += field_len/4;
>> +		else if ((type == EIR_UUID128_SOME) || (type == EIR_UUID128_ALL))
>> +			count += field_len/16;
>> +		len += field_len + 1;
>> +		eir_data += field_len + 1;
>> +	}
>> +
>> +	return count;
>> +}
>
> Variables should always be declared in the minimum scope possible. In
> the above function only the count and len variables need to be in the
> function scope whereas all other should be declared inside the while
> loop.
>
>> +static void get_uuids_eir(char **uuids, uint8_t *eir_data)
>> +{
>> +	uint8_t type;
>> +	uint8_t len = 0;
>> +	uint8_t field_len = 0;
>> +	int count = 0;
>> +	int size;
>> +	uuid_t service;
>> +	gboolean service_found;
>> +
>> +	/* Count UUID16, UUID32 and UUID128 */
>> +	while (len < EIR_DATA_LENGTH) {
>> +		type = eir_data[1];
>> +		field_len =  eir_data[0];
>> +		service_found = FALSE;
>
> Same comment regarding the scope of variables.
>
>> +		if ((type == EIR_UUID16_SOME) || (type == EIR_UUID16_ALL)) {
>> +			size = 2;
>> +			service.type = SDP_UUID16;
>> +			service_found = TRUE;
>> +		} else if ((type == EIR_UUID32_SOME) || (type == EIR_UUID32_ALL)) {
>> +			size = 4;
>> +			service.type = SDP_UUID32;
>> +			service_found = TRUE;
>> +		} else if ((type == EIR_UUID128_SOME) || (type == EIR_UUID128_ALL)) {
>> +			size = 16;
>> +			service.type = SDP_UUID128;
>> +			service_found = TRUE;
>> +		}
>> +
>> +		if (service_found) {
>
> I think it'd be more readable to have
>
> if (!service_found)
> 	continue;
>
> The two last operations in the loop still need to be executed to which
> the solution would be to use a for loop and have the commands in the
> third part (i.e. for (...; ...; <whatever needs to be done every time>)
> or use a label+goto.
>
>> +			uint8_t *data = &eir_data[2];
>> +			uint16_t val16;
>> +			uint32_t val32;
>> +			int i, k;
>> +
>> +			count = field_len/size;
>
> Space before and after /
>
>> +
>> +			/* Generate uuids in SDP format (EIR data is Little Endian) */
>> +			switch (service.type) {
>> +			case SDP_UUID16:
>> +				for (i = 0; i < count; i++) {
>> +					val16 = data[1];
>> +					val16 = (val16<<8) + data[0];
>> +					service.value.uuid16 = val16;
>> +					*uuids++ = bt_uuid2string(&service);
>> +					data += size;
>> +				}
>> +				break;
>> +			case SDP_UUID32:
>> +				for (i = 0; i < count; i++) {
>> +					val32 = data[3];
>> +					for (k = size-2 ; k >= 0; k--)
>> +						val32 = (val32<<8) + data[k];
>
> Space before and after <<
>
>> +					service.value.uuid32 = val32;
>> +					*uuids++ = bt_uuid2string(&service);
>> +					data += size;
>> +				}
>> +				break;
>> +			case SDP_UUID128:
>> +				for (i = 0; i < count; i++) {
>> +					for (k = 0; k < size; k++)
>> +						service.value.uuid128.data[k] = data[size-k-1];
>
> Space before and after -
>
> You're running into trouble with the 80-character line limit while still
> keeping the code readable, but imho the core issue is just a too complex
> and long function. Please consider if you could find a way to refactor
> or rearrange it somehow.
>
>>  void adapter_emit_device_found(struct btd_adapter *adapter,
>> -				struct remote_dev_info *dev);
>> +                               struct remote_dev_info *dev, uint8_t
>> *eir_data);
>
> Looks like a mixed tabs & spaces coding style violation.
>
>> diff --git a/src/sdpd-service.c b/src/sdpd-service.c
>> index 798e49d..5aa00f1 100644
>> --- a/src/sdpd-service.c
>> +++ b/src/sdpd-service.c
>> @@ -181,23 +181,30 @@ void create_ext_inquiry_response(const char *name,
>
> With your changes this function is growing quite ridiculously huge.
> Would there be any way to avoid that?
>
>> -		ptr += len + 2;
>> +		eir_len	 += (len + 2);
>
> Tab & space before the += (it should just be a space)
>
>>  		*ptr++ = (did_version & 0xff00) >> 8;
>> +		eir_len	 += 10;
>>  	}
>
> Same here.
>
>> +	/* Group all UUID128 types */
>> +	if (!truncated && (eir_len <= EIR_DATA_LENGTH - 2 )) {
>> +
>> +		list = services;
>> +		index = 0;
>> +
>> +		/* Store UUID128 in place, skipping first 2 bytes to insert type and
>> length later */
>
> Looks to me like this is beyond the 80-character limit.
>
>> +		uuid128 = ptr + 2;
>> +
>> +		for (; list; list = list->next) {
>> +			sdp_record_t *rec = (sdp_record_t *) list->data;
>> +
>> +			if (rec->svclass.type != SDP_UUID128)
>> +				continue;
>> +
>> +			/* Stop if not enough space to put next UUID128 */
>> +			if ((eir_len + 2 + SIZEOF_UUID128) > EIR_DATA_LENGTH) {
>> +				truncated = TRUE;
>> +				break;
>> +			}
>> +
>> +			/* Check for duplicates, EIR data is Little Endian	*/
>> +			for (i = 0; i < index; i++) {
>> +				for (k = 0; k < SIZEOF_UUID128; k++) {
>> +					if (uuid128[i*SIZEOF_UUID128 + k] !=
>
> Space before and after *
>
>> +						rec->svclass.value.uuid128.data[SIZEOF_UUID128 - k])
>
> 80-character limit exceeded
>
>> +			ptr	 = data + eir_len;
>
> Tab & space before = (it should be just a space)
>
>> +#define EIR_DATA_LENGTH  240
>> +
>> +#define EIR_FLAGS                   0x01  /* Flags */
>> +#define EIR_UUID16_SOME             0x02  /* 16-bit UUID, more
>> available */
>> +#define EIR_UUID16_ALL              0x03  /* 16-bit UUID, all listed */
>> +#define EIR_UUID32_SOME             0x04  /* 32-bit UUID, more
>> available */
>> +#define EIR_UUID32_ALL              0x05  /* 32-bit UUID, all listed */
>> +#define EIR_UUID128_SOME            0x06  /* 128-bit UUID, more
>> available */
>> +#define EIR_UUID128_ALL             0x07  /* 128-bit UUID, all listed
>> */
>> +#define EIR_NAME_SHORT              0x08  /* shortened local name */
>> +#define EIR_NAME_COMPLETE           0x09  /* complete local name */
>> +#define EIR_TX_POWER                0x0A  /* Transmit power level */
>> +#define OOB_CLASS_OF_DEVICE         0x0D  /* Class of Device (OOB only)
>> */
>> +#define OOB_SIMPLE_PAIRING_HASH_C   0x0E  /* Simple Pairing HashC (OOB
>> only) */
>> +#define OOB_SIMPLE_PAIRING_RAND_R   0x0F  /* Simple Pairing RandR (OOB
>> only) */
>> +#define EIR_DEVICE_ID               0x10  /* Device ID */
>> +#define EIR_MANF_DATA               0xFF  /* Manufacturer Specific Data
>> */
>> +
>> +#define SIZEOF_UUID128 16
>
> Do all of these defines really need to be in the sdpd.h header? At least
> stuff like SIZEOF_UUID128 should be moved into the .c file that uses it
> (if it's really needed at all).
>
> Johan
>



^ permalink raw reply

* Re: [PATCH] hciattach: Fix the timeout handling code
From: Johan Hedberg @ 2010-06-30 14:39 UTC (permalink / raw)
  To: Vladimir Davydov; +Cc: linux-bluetooth, Sergey Kovalev
In-Reply-To: <1277904079-10360-1-git-send-email-vladimir.davydov@promwad.com>

On Wed, Jun 30, 2010, Vladimir Davydov wrote:
> The variable 'retries' should be defined as static, or it will be always
> 0.
> ---
>  tools/hciattach.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)

Thanks. The patch is now upstream.

Johan

^ permalink raw reply

* [PATCH] hciattach: Fix the timeout handling code
From: Vladimir Davydov @ 2010-06-30 13:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Johan Hedberg, Sergey Kovalev, Vladimir Davydov

The variable 'retries' should be defined as static, or it will be always
0.
---
 tools/hciattach.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/hciattach.c b/tools/hciattach.c
index b13db1b..e772b6f 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -326,7 +326,8 @@ static int bcsp_max_retries = 10;
 static void bcsp_tshy_sig_alarm(int sig)
 {
 	unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries) {
 		retries++;
@@ -343,7 +344,8 @@ static void bcsp_tshy_sig_alarm(int sig)
 static void bcsp_tconf_sig_alarm(int sig)
 {
 	unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries){
 		retries++;
-- 
1.6.4.2


^ permalink raw reply related

* Re: [PATCH 0/3] SBC encoder optimizations (scale factors)
From: Siarhei Siamashka @ 2010-06-30 13:16 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20100630073239.GA23270@jh-x301>

[-- Attachment #1: Type: Text/Plain, Size: 241 bytes --]

On Wednesday 30 June 2010 07:32:39 Johan Hedberg wrote:
> All three patches have been pushed upstream. Thanks!

Thanks.

A few more SBC encoder performance optimizations will follow shortly :) 

-- 
Best regards,
Siarhei Siamashka

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: SBC encoder/decoder API & errors handling
From: Siarhei Siamashka @ 2010-06-30 13:07 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: Luiz Augusto von Dentz, linux-bluetooth, Lennart Poettering
In-Reply-To: <20100630085347.GA31839@jh-x301>

[-- Attachment #1: Type: Text/Plain, Size: 2451 bytes --]

On Wednesday 30 June 2010 08:53:47 Johan Hedberg wrote:
> Hi Luiz,
> 
> On Wed, Jun 30, 2010, Luiz Augusto von Dentz wrote:
> > audio/pcm_bluetooth.c:1060:		encoded = sbc_encode(&a2dp->sbc,
> > data->buffer, a2dp->codesize,
> > audio/pcm_bluetooth.c:1096:		encoded = sbc_encode(&a2dp->sbc, buff,
> > a2dp->codesize,
> 
> My patch already contained the fix for these two.
> 
> > audio/gstsbcenc.c:391:		consumed = sbc_encode(&enc->sbc, 
(gpointer) data,
> 
> This place actually passes NULL as the output parameter so no issue
> there.

Well, it is still kind of an issue because some types of errors are not 
detected here at all.

> I'll push in a minute the fix in two separate commits (the libsbc
> changes should be in an independent patch so they can easily be exported
> to external copies like pulseaudio).

Yes, I used exactly the same patch myself and it helped. It's a bit artificial 
problem and does not need an urgent fix. I found it by running a script which 
uses 'sbcenc' with lots with different permutations of configuration options 
(some of them are invalid) and logs md5 hashes of the encoded results. But as 
long as the SBC encoder is always used with valid settings, no problems should 
happen.

Anyway, API inconsistency is a bit ugly. Maybe it's better to always report 
errors as a negative function return value (and have real constants defined 
instead of some magic numbers)? Or just adjust encoding settings to the closest 
valid configuration automatically and never fail there?


Another SBC issue (I found this report just on the last weekend) is the missing 
support for the dynamically changing bitpool value:
https://tango.0pointer.de/pipermail/pulseaudio-discuss/2010-January/006042.html

It is a clear problem for the SBC decoder (in addition to the other issues like 
not so good audio quality and poor performance, which would have to be 
addressed eventually).

But SBC encoder could also make some use of this changing bitpool feature to 
adaptively change it when connection quality is not very good and audio would 
start skipping otherwise (due to the interference from wifi, walking away from 
the bluetooth dongle behind a concrete wall or anything else).

So would it be a good idea to just fix the issues in the bluez SBC code as we 
feel appropriate and then notify pulseaudio developers about the changes?

-- 
Best regards,
Siarhei Siamashka

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH] Add udev scripts to gitignore.
From: João Paulo Rechi Vita @ 2010-06-30 13:03 UTC (permalink / raw)
  To: João Paulo Rechi Vita, linux-bluetooth
In-Reply-To: <20100630095833.GA2866@jh-x301>

2010/6/30 Johan Hedberg <johan.hedberg@gmail.com>:
> Hi,
>
> On Tue, Jun 29, 2010, João Paulo Rechi Vita wrote:
>> +scripts/97-bluetooth.rules
>> +scripts/97-bluetooth-hid2hci.rules
>
> How do these files get created? I've never seen them in my bluez tree.
>

You have to enable udevrules during the configure phase. They were
probably leftover because most devs use bootstrap-configure script,
which pass --disable-udevrules to configure.

-- 
João Paulo Rechi Vita
http://jprvita.wordpress.com/

^ permalink raw reply

* Re: [PATCH] hciattach: Fix the timeout handling code
From: Johan Hedberg @ 2010-06-30 11:46 UTC (permalink / raw)
  To: Vladimir Davydov; +Cc: linux-bluetooth, Sergey Kovalev
In-Reply-To: <201006301441.25119.vladimir.davydov@promwad.com>

Hi Vladimir,

On Wed, Jun 30, 2010, Vladimir Davydov wrote:
> From: Vladimir Davydov <vladimir.davydov@promwad.com>
> 
> The variable 'retries' should be defined as static, or it will be always 0.

The patch doesn't apply cleanly:

Applying: hciattach: Fix the timeout handling code
fatal: corrupt patch at line 13
Patch failed at 0001 hciattach: Fix the timeout handling code

Maybe you could try git send-email instead?

> Signed-off-by: Vladimir Davydov <vladimir.davydov@promwad.com>

We don't use Signed-off-by in the userspace part of BlueZ, so please leave it
away. Otherwise the patch looked fine.

Johan

^ permalink raw reply

* [PATCH] hciattach: Fix the timeout handling code
From: Vladimir Davydov @ 2010-06-30 11:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Johan Hedberg, Sergey Kovalev

From: Vladimir Davydov <vladimir.davydov@promwad.com>

The variable 'retries' should be defined as static, or it will be always 0.

Signed-off-by: Vladimir Davydov <vladimir.davydov@promwad.com>

---
 tools/hciattach.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/hciattach.c b/tools/hciattach.c
index b13db1b..e772b6f 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -326,7 +326,8 @@ static int bcsp_max_retries = 10;
 static void bcsp_tshy_sig_alarm(int sig)
 {
 	unsigned char bcsp_sync_pkt[10] = 
{0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries) {
 		retries++;
@@ -343,7 +344,8 @@ static void bcsp_tshy_sig_alarm(int sig)
 static void bcsp_tconf_sig_alarm(int sig)
 {
 	unsigned char bcsp_conf_pkt[10] = 
{0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries){
 		retries++;
-- 
1.6.4.2

-- 
Vladimir Davydov
Senior Developer
Promwad Innovation Company
Web: www.promwad.com
22, Olshevskogo St.,
220073, Minsk,
BELARUS
Phone/Fax: +375 (17) 312–1246
E-mail: vladimir.davydov@promwad.com
Skype: v_davydov

^ permalink raw reply related

* Re: SBC encoder/decoder API & errors handling
From: Johan Hedberg @ 2010-06-30 11:03 UTC (permalink / raw)
  To: Siarhei Siamashka
  Cc: Luiz Augusto von Dentz, linux-bluetooth, Lennart Poettering
In-Reply-To: <201006301307.49874.siarhei.siamashka@gmail.com>

Hi Siarhei,

On Wed, Jun 30, 2010, Siarhei Siamashka wrote:
> So would it be a good idea to just fix the issues in the bluez SBC
> code as we feel appropriate and then notify pulseaudio developers
> about the changes?

Yes, I think that's a reasonable way to proceed.

Johan

^ permalink raw reply

* Re: [PATCH] Add udev scripts to gitignore.
From: Johan Hedberg @ 2010-06-30  9:58 UTC (permalink / raw)
  To: João Paulo Rechi Vita; +Cc: linux-bluetooth
In-Reply-To: <1277860131-3285-1-git-send-email-jprvita@gmail.com>

Hi,

On Tue, Jun 29, 2010, João Paulo Rechi Vita wrote:
> +scripts/97-bluetooth.rules
> +scripts/97-bluetooth-hid2hci.rules

How do these files get created? I've never seen them in my bluez tree.

Johan

^ permalink raw reply

* Re: Timeout in hciattach
From: Johan Hedberg @ 2010-06-30  9:50 UTC (permalink / raw)
  To: Vladimir Davydov; +Cc: linux-bluetooth, Sergey Kovalev
In-Reply-To: <201006171320.30987.vladimir.davydov@promwad.com>

Hi Vladimir,

On Thu, Jun 17, 2010, Vladimir Davydov wrote:
> I have found that in the latest release of the bluez4 (4.66) timeout in 
> hciattach doesn't work.
> 
> Look at this code of hciattach.c:
> 
> static void bcsp_tshy_sig_alarm(int sig)
> {
> 	unsigned char bcsp_sync_pkt[10] = 
> {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
> 	int len, retries = 0;
> 
> 	if (retries < bcsp_max_retries) {
> 		retries++;
> 		len = write(serial_fd, &bcsp_sync_pkt, 10);
> 		alarm(1);
> 		return;
> 	}
> 
> 	tcflush(serial_fd, TCIOFLUSH);
> 	fprintf(stderr, "BCSP initialization timed out\n");
> 	exit(1);
> }
> 
> The variable 'retries' will be always 0. Why is it not static? It was static 
> in oldest releases (3.33 for example).

It looks to me like this is a regression introduced by commit
72c6ed7e2d619048440ff528fca7fef59887fbaf from Marcel.

> I have attached simple patch to fix that.

Could you please send a patch in git format-patch format and also fix
the issue in in the other _alarm function (if you take a look at
Marcel's patch you'll see both places that need fixing).

Johan

^ permalink raw reply

* Re: SBC encoder/decoder API & errors handling
From: Johan Hedberg @ 2010-06-30  8:53 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Siarhei Siamashka, linux-bluetooth, Lennart Poettering
In-Reply-To: <AANLkTildwDBZR2U6AtxGEiq4Mv-PBnDoqY1xfqHHmzL2@mail.gmail.com>

Hi Luiz,

On Wed, Jun 30, 2010, Luiz Augusto von Dentz wrote:
> audio/pcm_bluetooth.c:1060:		encoded = sbc_encode(&a2dp->sbc,
> data->buffer, a2dp->codesize,
> audio/pcm_bluetooth.c:1096:		encoded = sbc_encode(&a2dp->sbc, buff,
> a2dp->codesize,

My patch already contained the fix for these two.

> audio/gstsbcenc.c:391:		consumed = sbc_encode(&enc->sbc, (gpointer) data,

This place actually passes NULL as the output parameter so no issue
there.

I'll push in a minute the fix in two separate commits (the libsbc
changes should be in an independent patch so they can easily be exported
to external copies like pulseaudio).

Johan

^ permalink raw reply

* Re: Is it valid BlueZ Serail-API ?
From: Johan Hedberg @ 2010-06-30  8:44 UTC (permalink / raw)
  To: Chanyeol,Park; +Cc: linux-bluetooth
In-Reply-To: <AANLkTinBv-1bUF3ccpMMWcpbAlVB9repG2zuluYMBtUR@mail.gmail.com>

Hi,

On Thu, Jun 24, 2010, Chanyeol,Park wrote:
> There is a log like the bottom.
> 
> Current Code doesn't have the below documents.(serial-api.txt) after
> the git-log , however their code is still alive.
> 
> I am little bit confused.
> 
> Could you tell me whethr their API are valid or not?
> 
> If you explain why you removed,  it would be helpul.
> 
> BR
> Chanyeol.Park
> 
> Remove old serial-api.txt documentation file
> author	Marcel Holtmann <marcel@holtmann.org>	
> 	Mon, 22 Dec 2008 07:10:37 +0000 (08:10 +0100)
> committer	Marcel Holtmann <marcel@holtmann.org>	
> 	Mon, 22 Dec 2008 07:10:37 +0000 (08:10 +0100)
> serial/Makefile.am 		patch | blob | history
> serial/serial-api.txt 	[deleted file] 	patch | blob | history

I think the API simply got moved to doc/serial-api.txt

Johan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox