From 2919e5add82966150586684b3efb43509d971a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 14 Aug 2009 11:12:50 +0200 Subject: [PATCH] gstutils: Add special random unit test for 64 scaling functions This tests 100000 random multiplications/divisions of all scaling function variants and compares the result with the result that is generated by GMP on the same input. For this check for GSL and GMP during configure but only use it for this single unit test. Testing functions were provided by Kipp Cannon --- configure.ac | 19 +++++ tests/check/Makefile.am | 2 + tests/check/gst/gstutils.c | 165 +++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/configure.ac b/configure.ac index ca0fcb9029..c079924fce 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,25 @@ if test "x$HAVE_WINSOCK2_H" = "xyes"; then AC_SUBST(WIN32_LIBS) fi +dnl check for GMP/GSL, used by the gst_util_uint64_scale unit test only +AG_GST_CHECK_LIBHEADER(GMP, gmp, + __gmpz_init_set_d, , + gmp.h, + GMP_LIBS="-lgmp" + AC_SUBST(GMP_LIBS) + AC_DEFINE(HAVE_GMP, [1],[Have GMP library])) +AG_GST_CHECK_LIBHEADER(GSL, gsl, + gsl_rng_uniform_int, -lgslcblas, + gsl/gsl_rng.h, + GSL_LIBS="-lgsl -lgslcblas" + AC_SUBST(GSL_LIBS) + AC_DEFINE(HAVE_GSL, [1],[Have GSL library])) + +AC_CHECK_LIB(rt, clock_gettime, [ + AC_DEFINE(HAVE_CLOCK_GETTIME, 1) + LIBS="$LIBS -lrt" +]) + dnl *** checks for types/defines *** dnl *** checks for structures *** diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 4c32289f58..3437792dbf 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -143,6 +143,8 @@ LDADD = $(top_builddir)/libs/gst/check/libgstcheck-@GST_MAJORMINOR@.la \ $(GST_OBJ_LIBS) \ $(CHECK_LIBS) +gst_gstutils_LDADD = $(LDADD) $(GSL_LIBS) $(GMP_LIBS) + libs_gdp_SOURCES = \ libs/gdp.c libs_gdp_CFLAGS = $(AM_CFLAGS) diff --git a/tests/check/gst/gstutils.c b/tests/check/gst/gstutils.c index ecf1e74fc0..e7a29df8e2 100644 --- a/tests/check/gst/gstutils.c +++ b/tests/check/gst/gstutils.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #define SPECIAL_POINTER(x) ((void*)(19283847+(x))) @@ -738,6 +742,160 @@ GST_START_TEST (test_binary_search) GST_END_TEST; +#ifdef HAVE_GSL +#ifdef HAVE_GMP + +#include +#include + +static guint64 +randguint64 (gsl_rng * rng, guint64 n) +{ + union + { + guint64 x; + struct + { + guint16 a, b, c, d; + } parts; + } x; + x.parts.a = gsl_rng_uniform_int (rng, 1 << 16); + x.parts.b = gsl_rng_uniform_int (rng, 1 << 16); + x.parts.c = gsl_rng_uniform_int (rng, 1 << 16); + x.parts.d = gsl_rng_uniform_int (rng, 1 << 16); + return x.x % n; +} + + +enum round_t +{ + ROUND_TONEAREST = 0, + ROUND_UP, + ROUND_DOWN +}; + +static guint64 +gmp_scale (guint64 x, guint64 a, guint64 b, enum round_t mode) +{ + mpz_t mp1, mp2; + if (!b) + /* overflow */ + return G_MAXUINT64; + mpz_init_set_ui (mp1, x); + mpz_init (mp2); + mpz_mul_ui (mp2, mp1, a); + switch (mode) { + case ROUND_TONEAREST: + mpz_add_ui (mp1, mp2, b / 2); + mpz_set (mp2, mp1); + break; + case ROUND_UP: + mpz_add_ui (mp1, mp2, b - 1); + mpz_set (mp2, mp1); + break; + case ROUND_DOWN: + break; + } + mpz_tdiv_q_ui (mp1, mp2, b); + x = mpz_get_ui (mp1); + mpz_clear (mp1); + mpz_clear (mp2); + return x; +} + +static void +_gmp_test_scale (gsl_rng * rng) +{ + guint64 bygst, bygmp; + guint64 a = randguint64 (rng, gsl_rng_uniform_int (rng, + 2) ? G_MAXUINT64 : G_MAXUINT32); + guint64 b = randguint64 (rng, gsl_rng_uniform_int (rng, 2) ? G_MAXUINT64 - 1 : G_MAXUINT32 - 1) + 1; /* 0 not allowed */ + guint64 val = randguint64 (rng, gmp_scale (G_MAXUINT64, b, a, ROUND_DOWN)); + enum round_t mode = gsl_rng_uniform_int (rng, 3); + const char *func; + + bygmp = gmp_scale (val, a, b, mode); + switch (mode) { + case ROUND_TONEAREST: + bygst = gst_util_uint64_scale_round (val, a, b); + func = "gst_util_uint64_scale_round"; + break; + case ROUND_UP: + bygst = gst_util_uint64_scale_ceil (val, a, b); + func = "gst_util_uint64_scale_ceil"; + break; + case ROUND_DOWN: + bygst = gst_util_uint64_scale (val, a, b); + func = "gst_util_uint64_scale"; + break; + } + fail_unless (bygst == bygmp, + "error: %s(): %" G_GUINT64_FORMAT " * %" G_GUINT64_FORMAT " / %" + G_GUINT64_FORMAT " = %" G_GUINT64_FORMAT ", correct = %" G_GUINT64_FORMAT + "\n", func, val, a, b, bygst, bygmp); +} + +static void +_gmp_test_scale_int (gsl_rng * rng) +{ + guint64 bygst, bygmp; + gint32 a = randguint64 (rng, G_MAXINT32); + gint32 b = randguint64 (rng, G_MAXINT32 - 1) + 1; /* 0 not allowed */ + guint64 val = randguint64 (rng, gmp_scale (G_MAXUINT64, b, a, ROUND_DOWN)); + enum round_t mode = gsl_rng_uniform_int (rng, 3); + const char *func; + + bygmp = gmp_scale (val, a, b, mode); + switch (mode) { + case ROUND_TONEAREST: + bygst = gst_util_uint64_scale_int_round (val, a, b); + func = "gst_util_uint64_scale_int_round"; + break; + case ROUND_UP: + bygst = gst_util_uint64_scale_int_ceil (val, a, b); + func = "gst_util_uint64_scale_int_ceil"; + break; + case ROUND_DOWN: + bygst = gst_util_uint64_scale_int (val, a, b); + func = "gst_util_uint64_scale_int"; + break; + } + fail_unless (bygst == bygmp, + "error: %s(): %" G_GUINT64_FORMAT " * %d / %d = %" G_GUINT64_FORMAT + ", correct = %" G_GUINT64_FORMAT "\n", func, val, a, b, bygst, bygmp); +} + +#define GMP_TEST_RUNS 100000 + +GST_START_TEST (test_math_scale_gmp) +{ + gsl_rng *rng = gsl_rng_alloc (gsl_rng_mt19937); + gint n; + + for (n = 0; n < GMP_TEST_RUNS; n++) + _gmp_test_scale (rng); + + gsl_rng_free (rng); +} + +GST_END_TEST; + +GST_START_TEST (test_math_scale_gmp_int) +{ + gsl_rng *rng = gsl_rng_alloc (gsl_rng_mt19937); + gint n; + + for (n = 0; n < GMP_TEST_RUNS; n++) + _gmp_test_scale_int (rng); + + gsl_rng_free (rng); +} + +GST_END_TEST; + +#endif +#endif + static Suite * gst_utils_suite (void) { @@ -752,6 +910,13 @@ gst_utils_suite (void) tcase_add_test (tc_chain, test_math_scale_ceil); tcase_add_test (tc_chain, test_math_scale_uint64); tcase_add_test (tc_chain, test_math_scale_random); +#ifdef HAVE_GSL +#ifdef HAVE_GMP + tcase_add_test (tc_chain, test_math_scale_gmp); + tcase_add_test (tc_chain, test_math_scale_gmp_int); +#endif +#endif + tcase_add_test (tc_chain, test_guint64_to_gdouble); tcase_add_test (tc_chain, test_gdouble_to_guint64); #ifndef GST_DISABLE_PARSE