cannam@154: /*********************************************************************** cannam@154: Copyright (c) 2017 Google Inc., Jean-Marc Valin cannam@154: Redistribution and use in source and binary forms, with or without cannam@154: modification, are permitted provided that the following conditions cannam@154: are met: cannam@154: - Redistributions of source code must retain the above copyright notice, cannam@154: this list of conditions and the following disclaimer. cannam@154: - Redistributions in binary form must reproduce the above copyright cannam@154: notice, this list of conditions and the following disclaimer in the cannam@154: documentation and/or other materials provided with the distribution. cannam@154: - Neither the name of Internet Society, IETF or IETF Trust, nor the cannam@154: names of specific contributors, may be used to endorse or promote cannam@154: products derived from this software without specific prior written cannam@154: permission. cannam@154: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" cannam@154: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE cannam@154: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE cannam@154: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE cannam@154: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR cannam@154: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF cannam@154: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS cannam@154: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN cannam@154: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) cannam@154: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE cannam@154: POSSIBILITY OF SUCH DAMAGE. cannam@154: ***********************************************************************/ cannam@154: cannam@154: #ifdef HAVE_CONFIG_H cannam@154: #include "config.h" cannam@154: #endif cannam@154: cannam@154: #include cannam@154: #include cannam@154: #include "celt/stack_alloc.h" cannam@154: #include "cpu_support.h" cannam@154: #include "SigProc_FIX.h" cannam@154: cannam@154: /* Computes the impulse response of the filter so we cannam@154: can catch filters that are definitely unstable. Some cannam@154: unstable filters may be classified as stable, but not cannam@154: the other way around. */ cannam@154: int check_stability(opus_int16 *A_Q12, int order) { cannam@154: int i; cannam@154: int j; cannam@154: int sum_a, sum_abs_a; cannam@154: sum_a = sum_abs_a = 0; cannam@154: for( j = 0; j < order; j++ ) { cannam@154: sum_a += A_Q12[ j ]; cannam@154: sum_abs_a += silk_abs( A_Q12[ j ] ); cannam@154: } cannam@154: /* Check DC stability. */ cannam@154: if( sum_a >= 4096 ) { cannam@154: return 0; cannam@154: } cannam@154: /* If the sum of absolute values is less than 1, the filter cannam@154: has to be stable. */ cannam@154: if( sum_abs_a < 4096 ) { cannam@154: return 1; cannam@154: } cannam@154: double y[SILK_MAX_ORDER_LPC] = {0}; cannam@154: y[0] = 1; cannam@154: for( i = 0; i < 10000; i++ ) { cannam@154: double sum = 0; cannam@154: for( j = 0; j < order; j++ ) { cannam@154: sum += y[ j ]*A_Q12[ j ]; cannam@154: } cannam@154: for( j = order - 1; j > 0; j-- ) { cannam@154: y[ j ] = y[ j - 1 ]; cannam@154: } cannam@154: y[ 0 ] = sum*(1./4096); cannam@154: /* If impulse response reaches +/- 10000, the filter cannam@154: is definitely unstable. */ cannam@154: if( !(y[ 0 ] < 10000 && y[ 0 ] > -10000) ) { cannam@154: return 0; cannam@154: } cannam@154: /* Test every 8 sample for low amplitude. */ cannam@154: if( ( i & 0x7 ) == 0 ) { cannam@154: double amp = 0; cannam@154: for( j = 0; j < order; j++ ) { cannam@154: amp += fabs(y[j]); cannam@154: } cannam@154: if( amp < 0.00001 ) { cannam@154: return 1; cannam@154: } cannam@154: } cannam@154: } cannam@154: return 1; cannam@154: } cannam@154: cannam@154: int main(void) { cannam@154: const int arch = opus_select_arch(); cannam@154: /* Set to 10000 so all branches in C function are triggered */ cannam@154: const int loop_num = 10000; cannam@154: int count = 0; cannam@154: ALLOC_STACK; cannam@154: cannam@154: /* FIXME: Make the seed random (with option to set it explicitly) cannam@154: so we get wider coverage. */ cannam@154: srand(0); cannam@154: cannam@154: printf("Testing silk_LPC_inverse_pred_gain() optimization ...\n"); cannam@154: for( count = 0; count < loop_num; count++ ) { cannam@154: unsigned int i; cannam@154: opus_int order; cannam@154: unsigned int shift; cannam@154: opus_int16 A_Q12[ SILK_MAX_ORDER_LPC ]; cannam@154: opus_int32 gain; cannam@154: cannam@154: for( order = 2; order <= SILK_MAX_ORDER_LPC; order += 2 ) { /* order must be even. */ cannam@154: for( shift = 0; shift < 16; shift++ ) { /* Different dynamic range. */ cannam@154: for( i = 0; i < SILK_MAX_ORDER_LPC; i++ ) { cannam@154: A_Q12[i] = ((opus_int16)rand()) >> shift; cannam@154: } cannam@154: gain = silk_LPC_inverse_pred_gain(A_Q12, order, arch); cannam@154: /* Look for filters that silk_LPC_inverse_pred_gain() thinks are cannam@154: stable but definitely aren't. */ cannam@154: if( gain != 0 && !check_stability(A_Q12, order) ) { cannam@154: fprintf(stderr, "**Loop %4d failed!**\n", count); cannam@154: return 1; cannam@154: } cannam@154: } cannam@154: } cannam@154: if( !(count % 500) ) { cannam@154: printf("Loop %4d passed\n", count); cannam@154: } cannam@154: } cannam@154: printf("silk_LPC_inverse_pred_gain() optimization passed\n"); cannam@154: return 0; cannam@154: }