From 8c5aea272f84cce6cedb82f13e7f6aae972a8f08 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Tue, 12 Jan 2016 16:32:11 +0100 Subject: [PATCH] tests: add benchmark for fast_atof() --- tests/CMakeLists.txt | 4 +- tests/main_test_core.c | 4 +- tests/test_core_benchmark_fast_atof.c | 183 ++++++++++++++++++++++++++ tests/test_core_internal.c | 97 +++++++------- 4 files changed, 240 insertions(+), 48 deletions(-) create mode 100644 tests/test_core_benchmark_fast_atof.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ecbc0d9..588397f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,10 +29,12 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/temp) set(GMIO_TEST_CORE_SRC main_test_core.c test_core.c + test_core_benchmark_fast_atof.c test_core_internal.c test_core_platform.c core_utils.c - stream_buffer.c) + stream_buffer.c + ../benchmarks/commons/benchmark_tools.c) if(GMIO_BUILD_SHARED_LIBS) # Note_1: MSVC wants it because internal symbols are not exported (GCC # exports all symbols) diff --git a/tests/main_test_core.c b/tests/main_test_core.c index c463717..0624e09 100644 --- a/tests/main_test_core.c +++ b/tests/main_test_core.c @@ -23,10 +23,10 @@ const char* test_core__stream(); const char* test_internal__byte_swap(); const char* test_internal__byte_codec(); const char* test_internal__fast_atof(); -const char* test_internal__gmio_fast_atof(); const char* test_internal__safe_cast(); const char* test_internal__stringstream(); const char* test_internal__string_utils(); +const char* test_internal__benchmark_gmio_fast_atof(); const char* test_platform__alignment(); const char* test_platform__global_h(); @@ -44,10 +44,10 @@ const char* all_tests() UTEST_RUN(test_internal__byte_swap); UTEST_RUN(test_internal__byte_codec); UTEST_RUN(test_internal__fast_atof); - UTEST_RUN(test_internal__gmio_fast_atof); UTEST_RUN(test_internal__safe_cast); UTEST_RUN(test_internal__stringstream); UTEST_RUN(test_internal__string_utils); + UTEST_RUN(test_internal__benchmark_gmio_fast_atof); UTEST_RUN(test_platform__alignment); UTEST_RUN(test_platform__global_h); diff --git a/tests/test_core_benchmark_fast_atof.c b/tests/test_core_benchmark_fast_atof.c new file mode 100644 index 0000000..ec5c00c --- /dev/null +++ b/tests/test_core_benchmark_fast_atof.c @@ -0,0 +1,183 @@ +/**************************************************************************** +** gmio +** Copyright Fougue (2 Mar. 2015) +** contact@fougue.pro +** +** This software is a reusable library whose purpose is to provide complete +** I/O support for various CAD file formats (eg. STL) +** +** This software is governed by the CeCILL-B license under French law and +** abiding by the rules of distribution of free software. You can use, +** modify and/ or redistribute the software under the terms of the CeCILL-B +** license as circulated by CEA, CNRS and INRIA at the following URL +** "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html". +****************************************************************************/ + +#include "utest_assert.h" + +#include "../benchmarks/commons/benchmark_tools.h" +#include "../src/gmio_core/internal/fast_atof.h" + +#include +#include + +static const float float_array[] = { + 1145816.0615274f, + 859213.75982427f, + 966810.0021625f, + 116009.39334184f, + -71263.236445963f, + 1632844.0273334f, + 56876.761679015f, + 1670907.7036338f, + 1437992.5029064f, + 706598.88550015f, + 1912856.6587869f, + -74873.963359219f, + 861707.30952253f, + 251769.8571327f, + 1699911.3574624f, + 187482.6645886f, + 635324.18922303f, + 825239.16816583f, + 923229.60096562f, + 1671951.443363f, + 1229446.7883787f, + 757413.85596684f, + -14473.833429848f, + 1322835.7150326f, + -33251.199514256f, + 1531123.3647313f, + 528501.5790856f, + 436167.23596871f, + 14397.062228246f, + 1454939.7571268f, + 1692972.0920012f, + 1780646.3084559f, + 989713.49335728f, + 1541628.0544557f, + 10818.210575179f, + 193697.32038756f, + 459958.03305877f, + 386664.66157262f, + 1424156.8543595f, + 1737569.8573131f, + 998766.07898565f, + 1498818.5395481f, + 1245966.4099132f, + 1455428.7210365f, + 197385.08439501f, + 879153.40041702f, + -82192.77676297f, + 899980.71459121f, + 442951.18727859f, + 429733.95261435f, + -91807.596567929f, + 242590.54984087f, + 38434.983528422f, + 1438265.2223754f, + 94147.7701972f, + 1883829.7321852f, + 692408.39047935f, + 1102390.5784368f, + 1195454.442173f, + 1016988.4061986f, + 329433.38976681f, + 34867.718878606f, + 1139500.6440764f, + 1105145.6145966f, + 857621.72278837f, + 385386.37328212f, + 99213.089933252f, + 1057370.9274909f, + 618583.85429652f, + 243663.42967547f, + 953197.6427665f, + 1965283.5770814f, + 1104619.5847935f, + 260492.339805f, + 234207.59892753f, + 1614202.0538515f, + 1189281.6673914f, + 1554272.0507617f, + 1025472.5255656f, + 1222277.3171599f, + 1453022.1682289f, + 1456530.4573889f, + -85452.126751399f, + 12215.028755467f, + 1387416.2917898f, + 1526189.9514246f, + 1610725.9704781f, + 190781.76379706f, + 854656.48162861f, + 1351074.6843419f, + 551066.49000713f, + 52031.184291482f, + 1173924.6147098f, + 723591.50886703f, + 1147671.5720946f, + 918000.17292518f, + 1489562.4640815f, + 509914.95117076f, + 716195.46181345f, + 1981909.6994968f, +}; + +static void test_internal__run_atof(float (*func_atof)(const char*)) +{ + size_t iter; + for (iter = 0; iter < 1000; ++iter) { + size_t i; + for (i = 0; i < GMIO_ARRAY_SIZE(float_array); ++i) { + char strbuff[512] = {0}; + const float f = float_array[i]; + float fres = 0.f; + sprintf(strbuff, "%f", f); + fres = func_atof(strbuff); + sprintf(strbuff, "%E", f); + fres = func_atof(strbuff); + } + } +} + +static float float_strtod(const char* str) +{ + return (float)strtod(str, NULL); +} + +static void benchmark_fast_atof(const char* dummy) +{ + GMIO_UNUSED(dummy); + test_internal__run_atof(&fast_atof); +} + +static void benchmark_strtod(const char* dummy) +{ + GMIO_UNUSED(dummy); + test_internal__run_atof(&float_strtod); +} + +const char* test_internal__benchmark_gmio_fast_atof() +{ + struct benchmark_cmp_arg bmk_arg[] = { + { "str->float", &benchmark_fast_atof, NULL, &benchmark_strtod, NULL }, + {0} + }; + struct benchmark_cmp_result bmk_res = {0}; + const struct benchmark_cmp_result_header header = { "fast_atof", "strtod" }; + struct benchmark_cmp_result_array bmk_res_array = {0}; + + benchmark_cmp_batch(2, bmk_arg, &bmk_res, NULL, NULL); + bmk_res_array.ptr = &bmk_res; + bmk_res_array.count = 1; + puts("\n"); + benchmark_print_results( + BENCHMARK_PRINT_FORMAT_MARKDOWN, + header, + bmk_res_array); + + UTEST_ASSERT((1.2*bmk_res.func1_exec_time_ms) < bmk_res.func2_exec_time_ms); + + return NULL; +} diff --git a/tests/test_core_internal.c b/tests/test_core_internal.c index f63db46..24ac849 100644 --- a/tests/test_core_internal.c +++ b/tests/test_core_internal.c @@ -24,6 +24,7 @@ #include "../src/gmio_core/internal/numeric_utils.h" #include "../src/gmio_core/internal/safe_cast.h" #include "../src/gmio_core/internal/stringstream.h" +#include "../src/gmio_core/internal/stringstream_fast_atof.h" #include "../src/gmio_core/internal/string_utils.h" #include @@ -60,29 +61,59 @@ const char* test_internal__byte_codec() return NULL; } -static gmio_bool_t gmio_test_calculation_atof(const char* value_str) +static void gmio_test_atof_fprintf_err( + const char* func_fast_atof_str, + const char* val_str, + float fast_val, + float std_val) { - const gmio_float32_t fast_value = fast_atof(value_str); - const gmio_float32_t std_value = (gmio_float32_t)strtod(value_str, NULL); - const gmio_bool_t accurate = - gmio_float32_ulp_equals(fast_value, std_value, 1); - if (!accurate) { - fprintf(stderr, - "*** ERROR: fast_atof() less accurate than strtod()\n" - " value_str : \"%s\"\n" - " fast_value: %.12f (%s) as_int: 0x%x\n" - " std_value : %.12f (%s) as_int: 0x%x\n" - " ulp_diff : %u\n", - value_str, - fast_value, - gmio_float32_sign(fast_value) > 0 ? "+" : "-", - gmio_convert_uint32(fast_value), - std_value, - gmio_float32_sign(std_value) > 0 ? "+" : "-", - gmio_convert_uint32(std_value), - gmio_float32_ulp_diff(fast_value, std_value)); + fprintf(stderr, + "*** ERROR: %s() less accurate than strtod()\n" + " value_str : \"%s\"\n" + " fast_value: %.12f (%s) as_int: 0x%x\n" + " std_value : %.12f (%s) as_int: 0x%x\n" + " ulp_diff : %u\n", + func_fast_atof_str, + val_str, + fast_val, + gmio_float32_sign(fast_val) > 0 ? "+" : "-", + gmio_convert_uint32(fast_val), + std_val, + gmio_float32_sign(std_val) > 0 ? "+" : "-", + gmio_convert_uint32(std_val), + gmio_float32_ulp_diff(fast_val, std_val)); +} + +static gmio_bool_t gmio_test_calculation_atof(const char* val_str) +{ + const gmio_float32_t std_val = (gmio_float32_t)strtod(val_str, NULL); + int accurate_count = 0; + + { /* Test fast_atof() */ + const gmio_float32_t fast_val = fast_atof(val_str); + if (gmio_float32_ulp_equals(fast_val, std_val, 1)) + ++accurate_count; + else + gmio_test_atof_fprintf_err("fast_atof", val_str, fast_val, std_val); } - return accurate; + + { /* Test gmio_stringstream_fast_atof() */ + char iobuff[512] = {0}; + struct gmio_ro_buffer ibuff = gmio_ro_buffer(val_str, strlen(val_str), 0); + struct gmio_stringstream sstream = gmio_stringstream( + gmio_istream_buffer(&ibuff), + gmio_string(iobuff, 0, GMIO_ARRAY_SIZE(iobuff))); + const gmio_float32_t fast_val = gmio_stringstream_fast_atof(&sstream); + if (gmio_float32_ulp_equals(fast_val, std_val, 1)) { + ++accurate_count; + } + else { + gmio_test_atof_fprintf_err( + "gmio_stringstream_fast_atof", val_str, fast_val, std_val); + } + } + + return accurate_count == 2; } const char* test_internal__fast_atof() @@ -124,30 +155,6 @@ const char* test_internal__fast_atof() return NULL; } -const char* test_internal__gmio_fast_atof() -{ - static const char fstr[] = "1234.567E05"; - const float f1 = fast_atof(fstr); - - { - char strbuff[2048] = {0}; - struct gmio_stringstream sstream = {0}; - struct gmio_ro_buffer streambuff = { fstr, sizeof(fstr) - 1, 0 }; - float f2; - - sstream.stream = gmio_istream_buffer(&streambuff); - sstream.strbuff.ptr = &strbuff[0]; - sstream.strbuff.max_len = sizeof(strbuff) - 1; - gmio_stringstream_init(&sstream); - - f2 = gmio_stringstream_fast_atof(&sstream); - - UTEST_ASSERT(gmio_float32_ulp_equals(f1, f2, 1)); - } - - return NULL; -} - const char* test_internal__safe_cast() { #if GMIO_TARGET_ARCH_BIT_SIZE > 32